Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't a %en0 suffix work to connect a link-local IPv6 TCP socket in Python?

A week or so ago someone on StackOverflow asked why their Python code for connecting to an IPv6 link-local address wasn't working, and I replied that since it was a link-local address they needed to add a %en0 (or whatever the desired local-interface-name is) suffix to their target IP address. I thought I knew what I was talking about, so I didn't actually test my suggestion before answering (shame on me!).

Today I went to use that same technique for myself, only to find that it doesn't seem to work. :^( That is, this code does not work:

>>> from socket import *
>>> s = socket(AF_INET6, SOCK_STREAM)
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in connect
socket.error: [Errno 65] No route to host

The following code, on the other hand, DOES work (with or without the %en0 suffix):

>>> from socket import *
>>> s = socket(AF_INET6, SOCK_STREAM)
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001, 0, 6))
>>> 

... but I don't like doing it that way, because in order to figure out which scope ID integer to supply for the last argument, I have to execute a bunch of not-very-portable code to iterate over the local interfaces list, find the interface named 'en0', and extract its scope ID, which is more complexity overhead than I'd like to have.

Given that connect() is accepting the %en0 suffix to the IP address, why isn't it actually using it as expected to determine the scope ID?

FWIW, I am testing with Python 2.6.1 under MacOS/X 10.6.4.

like image 590
Jeremy Friesner Avatar asked Oct 27 '10 05:10

Jeremy Friesner


1 Answers

This is the correct way to do an ipv6 connection:

>>> addrinfo = getaddrinfo('fe80::225:ff:fecd:5aa0%en0', 2001, AF_INET6, SOCK_STREAM)
>>> addrinfo
[(30, 1, 6, '', ('fe80::225:ff:fecd:5aa0%en0', 2001, 0, 4))]
>>> (family, socktype, proto, canonname, sockaddr) = addrinfo[0]
>>> s = socket(family, socktype, proto)
>>> s.connect(sockaddr)

getaddrinfo() will return the correct numerical scope and flow information for you.

like image 186
Jerub Avatar answered Oct 13 '22 23:10

Jerub