Last active
October 1, 2024 19:51
-
-
Save pklaus/289646 to your computer and use it in GitHub Desktop.
Python: List all Network Interfaces On Computer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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)) |
Is this linux only as the link suggests? I am unsuccessful running it on mac OSX.
Yes, this is linux only.
thanks!
How about IPv6?
https://pypi.python.org/pypi/netifaces
just found this, really useful. hope it helps.
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])))
Hey! dude Thanks!
If I want include this function in some project, this module have a license?
Best Regards!
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
namestr = names.tostring()
New in version 3.2: tostring()
is renamed to tobytes()
for clarity.
array.array.tobytes
impossible to get fcntl module when I import it
Why?
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
thanks.