netaddr / netaddr

A network address manipulation library for Python
https://netaddr.readthedocs.io/en/latest/
Other
780 stars 177 forks source link

IPv6 validation seems to not check zone_id correctly #140

Open harlowja opened 7 years ago

harlowja commented 7 years ago

Looking at the following:

https://tools.ietf.org/html/rfc4007#page-15

It appears that the zone_id has certain restrictions but netaddr isn't checking those.

>>> x = 'fe80::1%'
>>> netaddr.valid_ipv6(x)
True

Apparently one of the checks is that the zone_id can't be null (which it is in the above).

sileht commented 7 years ago

I don't think this is a netaddr issue, this method is just a wrapper around _socket methods. The wrapper and the builtin socket methods implementation doesn't have such issue.

>>> import netaddr, netaddr.fbsocket
>>> x = 'fe80::1%'
>>> netaddr.valid_ipv6(x)
False
>>> netaddr.fbsocket.inet_pton(netaddr.fbsocket.AF_INET6, x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/cdt.C6o62gPN/venv/local/lib/python2.7/site-packages/netaddr/fbsocket.py", line 196, in inet_pton
    [_pack('>H', int(i, 16)) for i in l_suffix]
ValueError: invalid literal for int() with base 16: '1%'

And my _socket module work as expected, so that looks like yours is buggy :)

>>> import _socket
>>> _socket.inet_pton(_socket.AF_INET6, x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.error: illegal IP address string passed to inet_pton
sileht commented 7 years ago

I think at least on Linux, valid_ipv6 doesn't support zone_id at all.

MEschenbacher commented 1 year ago

We've now come across the issue and it looks to be a fundamental one. It appears that netaddr is not considering IPv6 with zone_id as IPv6.

In our usecase, we configure IPv6 link local addresses for daemons to bind to and communicate with. We're using the ansible netaddr/utils filters to detect and modify IPv6 addresses (which internally make heavy use of netaddr, if I'm correct in reading through the source):

Example playbook:

---
- hosts: localhost
  tasks:
    - debug:
        msg:
          - "{{ 'fe80::1%ens18.18'|ansible.utils.ipwrap }} we believe should output [fe80::1%ens18.18]"
          - "{{ 'fe80::1%ens18.18'|ansible.utils.ipv6 }} we believe should output true"

Is fe80::1%eth1 a valid IPv6? Should it be identifyable as such? https://datatracker.ietf.org/doc/html/rfc4007#section-11 specifies that in order to prevent ambiguity of non-global IPv6 addresses, one should use the zone_id i.e. %zone_id.

jstasiak commented 8 months ago

Is fe80::1%eth1 a valid IPv6? Should it be identifyable as such?

These are great questions. I'm entirely sure right now, need to sleep on this. I don't think this library is prepared for IPv6 scope zones.