jack
jack

Reputation: 17881

Bind IPv6 address to Python socket as source ip address

I formerly used the code below to bind IPv4 address to Python socket as source ip address.

import socket
true_socket = socket.socket
def bound_socket(*a, **k):
    sock = true_socket(*a, **k)
    sock.bind((sourceIP, 0))
    return sock
socket.socket = bound_socket

Does above code work for IPv6 address? If not, how can I bind an IPv6 address?

Thanks in advance!

Upvotes: 8

Views: 13097

Answers (3)

glglgl
glglgl

Reputation: 91017

If you really want an extensive solution, you could extend your solution to use getaddrinfo():

import socket
l = socket.getaddrinfo(None, "", 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
for i in l: print i

This gives

(2, 1, 6, '', ('0.0.0.0', 0))
(10, 1, 6, '', ('::', 0, 0, 0))

These are the parameters you should create a socket with:

s = socket.socket(i[0], i[1], i[2])
if i[0] == AF_INET6: s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
s.bind(i[4])

Now you have as many sockets as you have protocols and you can use them. (Alas, the IPV6_V6ONLY doesn't work under older Windows versions...)

If you have a given host name/IP to bind to, do

l = socket.getaddrinfo("mylocalIP", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)

and it will choose the correct address/protocol family for you:

>>> socket.getaddrinfo("::1", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(10, 1, 6, '', ('::1', 0, 0, 0))]
>>> socket.getaddrinfo("127.0.0.1", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(2, 1, 6, '', ('127.0.0.1', 0))]
>>> socket.getaddrinfo("localhost", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(10, 1, 6, '', ('::1', 0, 0, 0)), (2, 1, 6, '', ('127.0.0.1', 0))]
>>> socket.getaddrinfo("192.168.1.32", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(2, 1, 6, '', ('192.168.1.32', 0))]

etc.

2 vs 10 are AF_INET vs. AF_INET6; socket.AI_PASSIVE means that you need this address for bind()ing.

Upvotes: 4

Samy Vilar
Samy Vilar

Reputation: 11100

you can try this, to get an IPV6 address, it is recommend that you use socket.getaddrinfo it will return all the different address both IPV4 and IPV6, you can bind them all or just which ever one you want/need.

import socket
def bound_socket(*a, **k):
    sock = socket.socket(*a, **k)
    if socket.AF_INET6 in a:
        if not socket.has_ipv6:
            raise ValueError("There's no support for IPV6!")
        else:
            address = [addr for addr in socket.getaddrinfo(source_ip, None)
                        if socket.AF_INET6 == addr[0]] # You ussually want the first one.
            if not address:
                raise ValueError("Couldn't find ipv6 address for source %s" % source_ip)
            sock.bind(address[0][-1])
    else:
        sock.bind((source_ip, 0))
    return sock

Upvotes: 6

mhawke
mhawke

Reputation: 87054

This should do the trick... set the address family.

import socket
s = socket.socket(family=socket.AF_INET6)
s.bind(('::1', 1234))

Upvotes: 3

Related Questions