Length of IPv6 address string.

Seeing the recent security release, I’m reminded of a very minor nit that we need to deal with.

The maximum length of the string representation of valid IPv6 addresses is not 39. It’s also not 45 as identified by RFC 4291: IP Version 6 Addressing Architecture for handling the IPv4-style dotted-notation. (POSIX also defines the string representation of an IPv6 address to be 46, which is 45 + the null byte.)

Technically, the maximum length is unbounded because the zone_id specification is defined as being implementation-defined. (See RFC 4007 - IPv6 Scoped Address Architecture) However, as that wouldn’t be considered practical, I would think that 54 might be considered a reasonable upper limit. (That’s 39 for the standard IPv6 address notation, the ‘%’ for the zone identifier, and 14 characters for an interface name, which should be sufficient for all practical purposes.)

This only affects the form field, because the PostgreSQL inet data type does not store the zone_id in that field. An address specified with with a zone_id needs to be split into two fields, unless its going to be stored as a string. (This comes with a whole different set of trade-offs.)

Anyway, I freely acknowledge that this does not fit within the general “80%” guidelines. I’m not expecting this to be changed - but did want to document it here for general reference.

1 Like

This sounds like something which could be easily changed while still addressing the security issue, or not? Previously there wasn’t a limit at all, and that was the problem – not 39 or 54 characters.

Hi Ken,

We’ve discussed the maximum length while working on the security patch, considering 39, 45 (to allow IPv4-mapped IPv6 addresses), or something bigger like 100 (to allow scope 99% of zone IDs). Ultimately we decided to use 39 to be consistent with django.db.models.GenericIPAddressField. It’s worth mentioning that it can be customized by providing the max_length argument.

Best,
Mariusz

1 Like

Hi Mariusz!

First, in the interest of full transparency - for me, this is an academic exercise. For various reasons going back about 10 years, we don’t currently use the GenericIPAddressField. (Handling of the zone info being the biggest.) So this isn’t a problem for us. Mostly, I just got curious about it when reading about the release.

I think there may still be an incongruity here with PostgreSQL. (It’s just not what I thought it was.) The Django GenericIPAddressField maps this to the inet data type, which allows the subnet to be stored in one field with the address.

Using Python 3.12.8 / Django 5.1.5
Given this model:

class IpTest(models.Model):
    ip = models.GenericIPAddressField()

This works:

In [1]: from bt.models import IpTest

In [2]: ip_test = IpTest(ip='1234:5678:9abc:def0:2468:ace0:1357:9bdf/120')

In [3]: ip_test.save()

In [4]: ip_test.ip
Out[4]: '1234:5678:9abc:def0:2468:ace0:1357:9bdf/120'

In [5]: 

Now, if I do the following:

In [8]: class IpForm(forms.ModelForm):
   ...:     class Meta:
   ...:         model = IpTest
   ...:         fields = ['ip']
   ...: 
...

In [13]: ip_form = IpForm({'ip': '1234:5678:9abc:def0:2468:ace0:1357:9fff/120'}, instance=ip_test)

In [14]: ip_form.is_valid()
Out[14]: False

In [15]: ip_form.errors
Out[15]: {'ip': ['This is not a valid IPv6 address.']}

In [16]: 

but:

In [19]: ip_test.ip = '1234:5678:9abc:def0:2468:ace0:1357:9fff/120'

In [20]: ip_test.save()

In [21]: ip_test.ip
Out[21]: '1234:5678:9abc:def0:2468:ace0:1357:9fff/120'

In [22]: 

It turns out that this is not an issue with the field length, but with the validation of the address containing a /.

Is this worth worrying about? :man_shrugging: I just think that it might be considered a problem with a form rendering a field with an existing value, that cannot be submitted because the form doesn’t accept that value.

Cheers,
Ken