Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python: List all Network Interfaces On Computer
"""
Determine IPv4 addresses on a Linux machine via the socket interface.
Thanks @bubthegreat the changes to make it Py2/3 compatible and the helpful
code comments: https://gist.github.com/pklaus/289646#gistcomment-2396272
This version has all comments removed for brevity.
"""
import socket
import array
import struct
import fcntl
def get_local_interfaces():
""" Returns a dictionary of name:ip key value pairs. """
MAX_BYTES = 4096
FILL_CHAR = b'\0'
SIOCGIFCONF = 0x8912
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
names = array.array('B', MAX_BYTES * FILL_CHAR)
names_address, names_length = names.buffer_info()
mutable_byte_buffer = struct.pack('iL', MAX_BYTES, names_address)
mutated_byte_buffer = fcntl.ioctl(sock.fileno(), SIOCGIFCONF, mutable_byte_buffer)
max_bytes_out, names_address_out = struct.unpack('iL', mutated_byte_buffer)
namestr = names.tobytes()
namestr[:max_bytes_out]
bytes_out = namestr[:max_bytes_out]
ip_dict = {}
for i in range(0, max_bytes_out, 40):
name = namestr[ i: i+16 ].split(FILL_CHAR, 1)[0]
name = name.decode('utf-8')
ip_bytes = namestr[i+20:i+24]
full_addr = []
for netaddr in ip_bytes:
if isinstance(netaddr, int):
full_addr.append(str(netaddr))
elif isinstance(netaddr, str):
full_addr.append(str(ord(netaddr)))
ip_dict[name] = '.'.join(full_addr)
return ip_dict
if __name__ == "__main__":
for iface, ip in get_local_interfaces().items():
print("{ip:15s} {iface}".format(ip=ip, iface=iface))
@serpentdark

This comment has been minimized.

Copy link

@serpentdark serpentdark commented Jun 28, 2013

thanks.

@mysteryDate

This comment has been minimized.

Copy link

@mysteryDate mysteryDate commented Sep 3, 2013

Is this linux only as the link suggests? I am unsuccessful running it on mac OSX.

@EmilHernvall

This comment has been minimized.

Copy link

@EmilHernvall EmilHernvall commented Jan 30, 2014

Yes, this is linux only.

@rongyi

This comment has been minimized.

Copy link

@rongyi rongyi commented Dec 9, 2014

thanks!

@emmaping

This comment has been minimized.

Copy link

@emmaping emmaping commented Mar 30, 2016

How about IPv6?

@zhanglongqi

This comment has been minimized.

Copy link

@zhanglongqi zhanglongqi commented Apr 19, 2016

https://pypi.python.org/pypi/netifaces
just found this, really useful. hope it helps.

@daerlnaxe

This comment has been minimized.

Copy link

@daerlnaxe daerlnaxe commented Nov 6, 2017

For python3.6 debugged:

# Use those functions to enumerate all interfaces available on the system using Python.
# found on <http://code.activestate.com/recipes/439093/#c1>

import socket
import fcntl
import struct
import array

def all_interfaces():
    max_possible = 128  # arbitrary. raise if needed.
    obytes = max_possible * 32
    deb = b'\0'

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    names = array.array('B', deb * obytes)
    outbytes = struct.unpack('iL', fcntl.ioctl(
        s.fileno(),
        0x8912,  # SIOCGIFCONF
        struct.pack('iL', obytes, names.buffer_info()[0])
    ))[0]

    namestr = names.tostring()

    lst = []
    for i in range(0, outbytes, 40):
        name = namestr[ i: i+16 ].split( deb, 1)[0]
        name = name.decode()
        #iface_name = namestr[ i : i+16 ].split( deb, 1 )[0]
        ip   = namestr[i+20:i+24]
        lst.append((name, ip))
    return lst

def format_ip(addr):
    return f'{addr[0]}.{addr[1]}.{addr[2]}.addr{3}'


ifs = all_interfaces()
for i in ifs:
    print ( f"\t{i[0]}\t: %s" % (format_ip(i[1])))
@rozvows

This comment has been minimized.

Copy link

@rozvows rozvows commented Dec 7, 2017

Hey! dude Thanks!

If I want include this function in some project, this module have a license?

Best Regards!

@bubthegreat

This comment has been minimized.

Copy link

@bubthegreat bubthegreat commented Mar 29, 2018

Modified it to be python2 and python3 compatible:

""" Python2/Python3 compatible method to get local interfaces with sockets. """

import socket
import array
import struct
import fcntl

def get_local_interfaces():
    """ Returns a dictionary of name:ip key value pairs. """

    # Max possible bytes for interface result.  Will truncate if more than 4096 characters to describe interfaces.
    MAX_BYTES = 4096

    # We're going to make a blank byte array to operate on.  This is our fill char.
    FILL_CHAR = b'\0'

    # Command defined in ioctl.h for the system operation for get iface list
    # Defined at https://code.woboq.org/qt5/include/bits/ioctls.h.html under
    # /* Socket configuration controls. */ section.
    SIOCGIFCONF = 0x8912

    # Make a dgram socket to use as our file descriptor that we'll operate on.
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Make a byte array with our fill character.
    names = array.array('B', MAX_BYTES * FILL_CHAR)

    # Get the address of our names byte array for use in our struct.
    names_address, names_length = names.buffer_info()

    # Create a mutable byte buffer to store the data in
    mutable_byte_buffer = struct.pack('iL', MAX_BYTES, names_address)

    # mutate our mutable_byte_buffer with the results of get_iface_list.
    # NOTE: mutated_byte_buffer is just a reference to mutable_byte_buffer - for the sake of clarity we've defined them as
    # separate variables, however they are the same address space - that's how fcntl.ioctl() works since the mutate_flag=True
    # by default.
    mutated_byte_buffer = fcntl.ioctl(sock.fileno(), SIOCGIFCONF, mutable_byte_buffer)

    # Get our max_bytes of our mutated byte buffer that points to the names variable address space.
    max_bytes_out, names_address_out = struct.unpack('iL', mutated_byte_buffer)

    # Convert names to a bytes array - keep in mind we've mutated the names array, so now our bytes out should represent
    # the bytes results of the get iface list ioctl command.
    namestr = names.tostring()

    namestr[:max_bytes_out]

    bytes_out = namestr[:max_bytes_out]

    # Each entry is 40 bytes long.  The first 16 bytes are the name string.
    # the 20-24th bytes are IP address octet strings in byte form - one for each byte.
    # Don't know what 17-19 are, or bytes 25:40.
    ip_dict = {}
    for i in range(0, max_bytes_out, 40):
        name = namestr[ i: i+16 ].split(FILL_CHAR, 1)[0]
        name = name.decode('utf-8')
        ip_bytes   = namestr[i+20:i+24]
        full_addr = []
        for netaddr in ip_bytes:
            if isinstance(netaddr, int):
                full_addr.append(str(netaddr))
            elif isinstance(netaddr, str):
                full_addr.append(str(ord(netaddr)))
        ip_dict[name] = '.'.join(full_addr)

    return ip_dict
@Searge

This comment has been minimized.

Copy link

@Searge Searge commented Apr 30, 2021

namestr = names.tostring()

New in version 3.2: tostring() is renamed to tobytes() for clarity.
array.array.tobytes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment