Skip to content

Instantly share code, notes, and snippets.

@pklaus
Last active March 15, 2024 15:32
Show Gist options
  • Star 45 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save pklaus/289646 to your computer and use it in GitHub Desktop.
Save pklaus/289646 to your computer and use it in GitHub Desktop.
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))
@emmaping
Copy link

How about IPv6?

@zhanglongqi
Copy link

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

@daerlnaxe
Copy link

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
Copy link

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
Copy link

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
Copy link

Searge commented Apr 30, 2021

namestr = names.tostring()

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

@BAHYAO
Copy link

BAHYAO commented Jun 10, 2021

impossible to get fcntl module when I import it

Why?

@pklaus
Copy link
Author

pklaus commented Jun 10, 2021

impossible to get fcntl module when I import it

Why?

Impossible to answer if you don't state the operating system you're on and the Python version you're using.

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