etingof / pysnmp

Python SNMP library
http://snmplabs.com/pysnmp/
BSD 2-Clause "Simplified" License
568 stars 188 forks source link

pysnmp doesn't support IPv6 link-local addresses #445

Open comotion opened 1 year ago

comotion commented 1 year ago

IPv6 link-local addresses are often the only way to reliably find an unconfigured switch.

If I do snmpwalk [fe80::abd:43ff:fe75:bfc5%ens3f0] -u admin (MD5, no auth, SNMPv3) I get the expected tree however, if I modify the fetch-variables-over-ipv6.py example to use this same addres, I get

python3 fetch-variables-over-ipv6.py 
Traceback (most recent call last):
  File "fetch-variables-over-ipv6.py", line 47, in <module>
    config.addTargetAddr(
  File "/usr/lib/python3/dist-packages/pysnmp/entity/config.py", line 305, in addTargetAddr
    transportAddress = TransportAddressIPv6(transportAddress)
  File "/usr/lib/python3/dist-packages/pyasn1/type/univ.py", line 819, in __init__
    base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
  File "/usr/lib/python3/dist-packages/pyasn1/type/base.py", line 240, in __init__
    value = self.prettyIn(value)
  File "<string>", line 248, in prettyIn
OSError: illegal IP address string passed to inet_pton

The immediate problem seems to be that the link-local address is parsed by inet_pton, however there is an underlying assumption that IPv6 addresses are just [(p,port,family) tuples, while the complete struct also includes a "zone info" that indicates the correct interface which must also be passed to the socket call and shouldn't be stripped:

>>> from socket import *
>>> a = getaddrinfo('fe80::abd:43ff:fe75:bfc5%ens3f0', 161, AF_INET6, SOCK_DGRAM)
>>> a[0][4]
('fe80::abd:43ff:fe75:bfc5', 161, 0, 7) # <--- notice the interface 7 here
lextm commented 11 months ago

You should read #429 to learn why posting here isn't the right thing to do in the future.

About this specific error, your modification of fetch-variables-over-ipv6.py matters and must be revealed. Note that socket.inet_pton(socket.AF_INET6, '[fe80::abd:43ff:fe75:bfc5%ens3f0]') produces the same error, but socket.inet_pton(socket.AF_INET6, 'fe80::abd:43ff:fe75:bfc5%ens3f0') works flawlessly.