Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reliably get IPV6 Address in Python

at the moment I do:

def get_inet_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('mysite.com', 80))
    return s.getsockname()[0]

This was based on: Finding local IP addresses using Python's stdlib

However, This looks a bit dubious. As far as I can tell, it opens a socket to mysite.com:80, and then returns the first address for that socket, assuming it to be an IPv4 address. This seems a bit dodgy... i dont think we can ever guaranteee that to be the case.

Thats my first question, is it safe? On an IPv6-enable server, could the IPv6 address ever be returned unexpectedly?

My second question, is how do I get the IPv6 address in a similar way. Im going to modify the function to take an optional ipv6 paramater.

like image 955
James Bennet Avatar asked Apr 29 '13 10:04

James Bennet


2 Answers

The question is, do you just want to connect, or do you really want the address?

If you just want to connect, you can do

s = socket.create_connection(('mysite.com', 80))

and have the connection established.

However, if you are interested in the address, you can go one of these ways:

def get_ip_6(host, port=0):
    import socket
    # search only for the wanted v6 addresses
    result = socket.getaddrinfo(host, port, socket.AF_INET6)
    return result # or:
    return result[0][4][0] # just returns the first answer and only the address

or, to be closer to another, already presented solution:

def get_ip_6(host, port=0):
     # search for all addresses, but take only the v6 ones
     alladdr = socket.getaddrinfo(host,port)
     ip6 = filter(
         lambda x: x[0] == socket.AF_INET6, # means its ip6
         alladdr
     )
     # if you want just the sockaddr
     # return map(lambda x:x[4],ip6)
     return list(ip6)[0][4][0]
like image 106
glglgl Avatar answered Nov 12 '22 05:11

glglgl


You should be using the function socket.getaddrinfo()

Example code to get IPv6

def get_ip_6(host,port=80):
    # discard the (family, socktype, proto, canonname) part of the tuple
    # and make sure the ips are unique
    alladdr = list(
        set(
            map(
                lambda x: x[4],
                socket.getaddrinfo(host,port)
            )
        )
    )
    ip6 = filter(
        lambda x: ':' in x[0], # means its ip6
        alladdr
    )
    return ip6
like image 22
katharas Avatar answered Nov 12 '22 06:11

katharas