Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create IPv6 socket at python? Why got the socket.error: (22, 'Invalid argument')?

I want to ceate Ipv6 socket at python, I do it like this:

#!/usr/bin/env python
import sys
import struct
import socket

host = 'fe80::225:b3ff:fe26:576'
sa = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sa.bind((host , 50000))

But it failed:

socket.error: (22, 'Invalid argument') ?

Can anyone help me? thanks!

I redo it like this, but still cannot work

    >>>host = 'fe80::225:b3ff:fe26:576'
    >>>sa = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    >>>res = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
    >>>family, socktype, proto, canonname, sockaddr = res[0]
    >>>print sockaddr
('fe80::225:b3ff:fe26:576', 50001, 0, 0)
    >>>sa.bind(sockaddr)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<string>", line 1, in bind
socket.error: (22, 'Invalid argument')
like image 681
Jianzhong Avatar asked Sep 27 '10 07:09

Jianzhong


2 Answers

There are two parts to the problem

First Issue

You should use the sa.bind(sockaddr) where sockaddr is obtained from getaddrinfo

>>> HOST = 'localhost'
>>> PORT = 50007 
>>> res = socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
>>> family, socktype, proto, canonname, sockaddr = res[1]
>>> proto
17
>>> sockaddr
('fe80::1%lo0', 50007, 0, 1)

Second Issue

If you look at the example provided in the socket documentation at

  • http://docs.python.org/release/2.5.2/lib/module-socket.html

Socket accepts three arguments

socket( [family[, type[, proto]]])

As per the documentation

Create a new socket using the given address family, 
socket type and protocol number. The address family 
should be AF_INET (the default), AF_INET6 or AF_UNIX. 
The socket type should be SOCK_STREAM (the default), 
SOCK_DGRAM or perhaps one of the other "SOCK_" constants. 
The protocol number is usually zero and may be omitted in that case.

And if you used getaddressinfo to get the values for proto then the value is different from the default 0

But when I executed the following, I get a different protocol value - 17. You may want to investigate this too.

And of course socket.has_ipv6 is True for me.

like image 73
pyfunc Avatar answered Sep 28 '22 00:09

pyfunc


The other thing missing from the above is that fe80::* are link-local addresses.As such you can't technically use them without a Scope ID.
Just in case that didn't sink in, "link-local" means that the address can only be used on a specific link, but the corollary is that since the address is link-specific theoretically you could have that same address on more than one link.
Now granted that in most cases a link-local address is generated from the already unique hardware (EUI-48) address by converting it to an EUI-64 and then flipping on the U/L bit (see) but this is not the only way you can generate a link-local address and other mechanisms could result in re-using the address (I don't think there's anything that prohibits this). So now you know why it didn't work.
The next question is how do you fix it, or rather where do you get the Scope ID. This is unfortunately non-obvious. If you read the IPV6 RFCs that discuss "Scope" you find that it is defined in a general fashion. In practice if you are running this code in Linux (maybe also Windows/Mac?) you can use the interface index.

Note that there's currently a bug in nss-mdns such that .local names are returned with scope id always zero so in Linux using .local names basically doesn't work unless your code has already figured out the scope id and sets it by itself.

like image 29
JJ on SE Avatar answered Sep 27 '22 23:09

JJ on SE