-
-
Save sdeibel/eb1a01d79c512334531fe3eeb16b1ee9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/python | |
# Based on https://gist.github.com/provegard/1536682, which was | |
# Based on getifaddrs.py from pydlnadms [http://code.google.com/p/pydlnadms/]. | |
# Only tested on Linux and OS X! | |
import sys | |
from socket import AF_INET, AF_INET6, inet_ntop | |
from ctypes import ( | |
Structure, Union, POINTER, | |
pointer, get_errno, cast, | |
c_ushort, c_ubyte, c_byte, c_void_p, c_char_p, c_uint, c_int, c_uint8, c_uint16, c_uint32 | |
) | |
import ctypes.util | |
import ctypes | |
class struct_sockaddr(Structure): | |
if sys.platform == 'darwin': | |
_fields_ = [ | |
('sa_len', c_uint8), | |
('sa_family', c_uint8), | |
('sa_data', c_byte * 14),] | |
else: | |
_fields_ = [ | |
('sa_family', c_ushort), | |
('sa_data', c_byte * 14),] | |
class struct_sockaddr_in(Structure): | |
if sys.platform == 'darwin': | |
_fields_ = [ | |
('sin_len', c_uint8), | |
('sin_family', c_uint8), | |
('sin_port', c_uint16), | |
('sin_addr', c_byte * 4), | |
('sin_zero', c_byte * 8)] | |
else: | |
_fields_ = [ | |
('sin_family', c_ushort), | |
('sin_port', c_uint16), | |
('sin_addr', c_byte * 4)] | |
class struct_sockaddr_in6(Structure): | |
if sys.platform == 'darwin': | |
_fields_ = [ | |
('sin6_len', c_uint8), | |
('sin6_family', c_uint8), | |
('sin6_port', c_uint16), | |
('sin6_flowinfo', c_uint32), | |
('sin6_addr', c_byte * 16), | |
('sin6_scope_id', c_uint32)] | |
else: | |
_fields_ = [ | |
('sin6_family', c_ushort), | |
('sin6_port', c_uint16), | |
('sin6_flowinfo', c_uint32), | |
('sin6_addr', c_byte * 16), | |
('sin6_scope_id', c_uint32)] | |
class struct_ifaddrs(Structure): | |
pass | |
if sys.platform == 'darwin': | |
struct_ifaddrs._fields_ = [ | |
('ifa_next', POINTER(struct_ifaddrs)), | |
('ifa_name', c_char_p), | |
('ifa_flags', c_uint), | |
('ifa_addr', POINTER(struct_sockaddr)), | |
('ifa_netmask', POINTER(struct_sockaddr)), | |
('ifa_dstaddr', POINTER(struct_sockaddr)), | |
('ifa_data', c_void_p),] | |
else: | |
class union_ifa_ifu(Union): | |
_fields_ = [ | |
('ifu_broadaddr', POINTER(struct_sockaddr)), | |
('ifu_dstaddr', POINTER(struct_sockaddr)),] | |
struct_ifaddrs._fields_ = [ | |
('ifa_next', POINTER(struct_ifaddrs)), | |
('ifa_name', c_char_p), | |
('ifa_flags', c_uint), | |
('ifa_addr', POINTER(struct_sockaddr)), | |
('ifa_netmask', POINTER(struct_sockaddr)), | |
('ifa_ifu', union_ifa_ifu), | |
('ifa_data', c_void_p),] | |
libc = ctypes.CDLL(ctypes.util.find_library('c')) | |
def ifap_iter(ifap): | |
ifa = ifap.contents | |
while True: | |
yield ifa | |
if not ifa.ifa_next: | |
break | |
ifa = ifa.ifa_next.contents | |
def getfamaddr(sa): | |
family = sa.sa_family | |
addr = None | |
if family == AF_INET: | |
sa = cast(pointer(sa), POINTER(struct_sockaddr_in)).contents | |
addr = inet_ntop(family, sa.sin_addr) | |
elif family == AF_INET6: | |
sa = cast(pointer(sa), POINTER(struct_sockaddr_in6)).contents | |
addr = inet_ntop(family, sa.sin6_addr) | |
return family, addr | |
class NetworkInterface(object): | |
def __init__(self, name): | |
self.name = name | |
self.index = libc.if_nametoindex(name) | |
self.addresses = {} | |
def __str__(self): | |
return "%s [index=%d, IPv4=%s, IPv6=%s]" % ( | |
self.name, self.index, | |
self.addresses.get(AF_INET), | |
self.addresses.get(AF_INET6)) | |
def get_network_interfaces(): | |
ifap = POINTER(struct_ifaddrs)() | |
result = libc.getifaddrs(pointer(ifap)) | |
if result != 0: | |
raise OSError(get_errno()) | |
del result | |
try: | |
retval = {} | |
for ifa in ifap_iter(ifap): | |
name = ifa.ifa_name.decode("UTF-8") | |
i = retval.get(name) | |
if not i: | |
i = retval[name] = NetworkInterface(name) | |
family, addr = getfamaddr(ifa.ifa_addr.contents) | |
if addr: | |
if family not in i.addresses: | |
i.addresses[family] = list() | |
i.addresses[family].append(addr) | |
return retval.values() | |
finally: | |
libc.freeifaddrs(ifap) | |
if __name__ == '__main__': | |
print([str(ni) for ni in get_network_interfaces()]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment