Using socket.getaddrinfo to look up IP addresses

February 19, 2010

As sort of promised in the last entry, here's the Python code to look up IPv4 and IPv6 addresses for a host, using getaddrinfo(). As usual, this is condensed for WanderingThoughts and omits a modicum of error checking.

import socket
def gethostips(host, type=None):
    ips = set()
    if type:
        types = (type,)
    else:
        types = (socket.AF_INET,
                 socket.AF_INET6)
    for t in types:
        try: 
            res = socket.getaddrinfo(host, None,
                           t, socket.SOCK_STREAM)
        except socket.error:
            continue
        nips = set([x[4][0] for x in res])
        ips.update(nips)
    return list(ips)

Passed just the hostname, it returns both IPv4 and IPv6 addresses; passed an optional type argument, it returns just addresses of that type. If there's nothing available, you get an empty list. Addresses are returned in some arbitrary order that mixes IPv4 and IPv6 addresses; I'm going to call this a feature, although in real code I might be tempted to change it so that all IPv4 addresses are returned either first or last.

(Besides, if you care about pretty-printing things you want to have some kind of sorting function that puts IP addresses in ascending order.)

This isn't what you want for making connections; instead, this is the kind of utility function that you need when verifying the hostnames of IP addresses, when some of the IP addresses you're dealing with are now IPv6 addresses because you've started to IPv6-enable your programs. This intended use is one reason why it returns an empty list if getaddrinfo() returns nothing instead of raising an exception.

(Note that a really good IPv6 hostname lookup function is more complicated than the IPv4 version; done properly, it should convert IPv4 compatible and IPv4 mapped addresses into IPv4 addresses and do an IPv4 hostname lookup for them.)


Comments on this page:

From 65.172.155.228 at 2010-02-19 11:01:32:

You code undoes the sorting, so Eg. ipv6.net comes out in the wrong order. Also FYI, there is a prebuilt util to do this for you:

% getent ahosts ipv6.net
82.98.234.168   STREAM ipv6.net
82.98.234.168   DGRAM  
82.98.234.168   RAW    
2a00:1188:3:c::80 STREAM 
2a00:1188:3:c::80 DGRAM  
2a00:1188:3:c::80 RAW
By cks at 2010-02-19 12:28:48:

getent ahosts suffers from the same problem that raw getaddrinfo() does (and the problem that forces me to effectively undo its own sorting); on a machine where the Linux standard library doesn't think it can make IPv6 connections, it will refuse to return IPv6 addresses unless you specifically ask for them.

(This is particularly striking because 'getent ahostsv6' will fail on such a machine.)

By the way, 'getent ahosts' appears to be Linux-specific; on other machines it is 'getent hosts', and returns rather different information.

From 65.172.155.228 at 2010-02-19 15:59:36:

Ahh, I wouldn't have thought it would do much over just printing the getaddrinfo() returns :(.

glibc getent also has "getent hosts", which doesn't use getaddrinfo(). Which is really confusing, but apparently mandated by some POSIX std.

Written on 19 February 2010.
« Some notes on using socket.getaddrinfo()
Viral marketing versus word of mouth marketing »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Feb 19 01:59:18 2010
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.