ActiveState Code

Recipe 439093: get names of all "up" network interfaces (linux only)


Uses the SIOCGIFCONF ioctl to obtain a list of interfaces and extracts those names, returning them in a list of strings.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import socket
import fcntl
import struct
import array

def all_interfaces():
    max_possible = 128  # arbitrary. raise if needed.
    bytes = max_possible * 32
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    names = array.array('B', '\0' * bytes)
    outbytes = struct.unpack('iL', fcntl.ioctl(
        s.fileno(),
        0x8912,  # SIOCGIFCONF
        struct.pack('iL', bytes, names.buffer_info()[0])
    ))[0]
    namestr = names.tostring()
    return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]

Discussion

This solution should be faster than running ifconfig and parsing its output, and simpler than reading and parsing /proc/net/dev, since that will list all existing interfaces, whether active (up) or not.

This solution probably only works on Linux-- and possibly not all versions of even that-- since it depends on some C structures having a particular size and layout, as well as having the SIOCGIFCONF ioctl number (0x8912) hardcoded. I believe it could be adjusted, though, to work on other Unix systems.

Comments

  1. 1. At 10:07 a.m. on 25 jul 2007, Duane Voth said:

    struct ifconf has changed... I wish we didn't have to use constants for the structure offsets... For a 2.6.17 kernel the above offsets are incorrect. I've replaced the last line with:

        ...
        lst = []
        for i in range(0, outbytes, 40):
            name = namestr[i:i+16].split('\0', 1)[0]
            ip   = namestr[i+20:i+24]
            lst.append((name, ip))
        return lst
    
    def format_ip(addr):
        return str(ord(addr[0])) + '.' + \
               str(ord(addr[1])) + '.' + \
               str(ord(addr[2])) + '.' + \
               str(ord(addr[3]))
    
    
    ifs = all_interfaces()
    for i in ifs:
        print "%12s   %s" % (i[0], format_ip(i[1]))
    
  2. 2. At 10:17 a.m. on 25 jul 2007, Duane Voth said:

    The above is for a 64 bit kernel... Ah, structure offsets have not changed over the years for 32 bit kernels, my patch is for a 64 bit 2.6.17 kernel.

  3. 3. At 5:08 p.m. on 4 mar 2008, Guilherme Polo said:

    no need for format_ip. You could have done: socket.inet_ntoa(ip)

Sign in to comment