-
-
Save mrroot5/c2a37ffe5e08947ac7100f8d0e677a40 to your computer and use it in GitHub Desktop.
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
#!/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! | |
from socket import AF_INET, AF_INET6, inet_ntop | |
from ctypes import ( | |
Structure, Union, POINTER, | |
pointer, get_errno, cast, | |
c_ushort, c_byte, c_void_p, c_char_p, c_uint, c_int, c_uint16, c_uint32 | |
) | |
import ctypes.util | |
import ctypes | |
class struct_sockaddr(Structure): | |
_fields_ = [ | |
('sa_family', c_ushort), | |
('sa_data', c_byte * 14),] | |
class struct_sockaddr_in(Structure): | |
_fields_ = [ | |
('sin_family', c_ushort), | |
('sin_port', c_uint16), | |
('sin_addr', c_byte * 4)] | |
class struct_sockaddr_in6(Structure): | |
_fields_ = [ | |
('sin6_family', c_ushort), | |
('sin6_port', c_uint16), | |
('sin6_flowinfo', c_uint32), | |
('sin6_addr', c_byte * 16), | |
('sin6_scope_id', c_uint32)] | |
class union_ifa_ifu(Union): | |
_fields_ = [ | |
('ifu_broadaddr', POINTER(struct_sockaddr)), | |
('ifu_dstaddr', POINTER(struct_sockaddr)),] | |
class struct_ifaddrs(Structure): | |
pass | |
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