Created
March 31, 2022 19:30
-
-
Save exarkun/1e413822a925f5f366e3a8f8e5345bee 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
from cffi import FFI | |
from socket import inet_ntop, AF_INET, AF_INET6 | |
ffi = FFI() | |
ffi.cdef(""" | |
struct in_addr { | |
union { | |
struct { | |
unsigned char s_b1; | |
unsigned char s_b2; | |
unsigned char s_b3; | |
unsigned char s_b4; | |
} S_un_b; | |
struct { | |
unsigned short s_w1; | |
unsigned short s_w2; | |
} S_un_w; | |
unsigned long S_addr; | |
} S_un; | |
}; | |
struct sockaddr { | |
unsigned short sa_family; | |
char sa_data[14]; | |
}; | |
struct sockaddr_in { | |
short int sin_family; | |
unsigned short int sin_port; | |
struct in_addr sin_addr; | |
unsigned char sin_zero[8]; | |
}; | |
struct sockaddr_in6 { | |
unsigned char sin6_len; /* length of this structure */ | |
unsigned char sin6_family; /* AF_INET6 */ | |
uint16_t sin6_port; /* Transport layer port # */ | |
uint32_t sin6_flowinfo; /* IPv6 flow information */ | |
struct in6_addr sin6_addr; /* IPv6 address */ | |
}; | |
struct ifaddrs { | |
struct ifaddrs *ifa_next; /* Next item in list */ | |
char *ifa_name; /* Name of interface */ | |
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */ | |
struct sockaddr *ifa_addr; /* Address of interface */ | |
struct sockaddr *ifa_netmask; /* Netmask of interface */ | |
}; | |
int getifaddrs(struct ifaddrs **ifap); | |
void freeifaddrs(struct ifaddrs *ifa); | |
""") | |
_C = ffi.dlopen(None) | |
def interfaces(): | |
result = {} | |
# The memory allocated is garbage collected along with ifaddrs_p | |
ifaddrs_p = ffi.new("struct ifaddrs**") | |
if _C.getifaddrs(ifaddrs_p) == 0: | |
try: | |
# Success, read the values. | |
ifaddr = ifaddrs_p[0] | |
while ifaddr != ffi.NULL: | |
result.setdefault(ffi.string(ifaddr.ifa_name), []).append(sockaddr_to_address(ifaddr.ifa_addr)) | |
ifaddr = ifaddr.ifa_next | |
finally: | |
# The ifaddrs structs themselves are dynamically allocated by | |
# getifaddrs and need to be freed. | |
_C.freeifaddrs(ifaddrs_p[0]) | |
return result | |
def sockaddr_to_address(sockaddr): | |
if sockaddr.sa_family == AF_INET: | |
sockaddr_in = ffi.cast("struct sockaddr_in*", sockaddr) | |
sin_addr = ffi.addressof(sockaddr_in, "sin_addr") | |
return inet_ntop(AF_INET, ffi.buffer(sin_addr)[0:ffi.sizeof("struct in_addr")]) | |
elif sockaddr.sa_family == AF_INET6: | |
sockaddr_in6 = ffi.cast("struct sockaddr_in6*", sockaddr) | |
sin6_addr = ffi.addressof(sockaddr_in6, "sin6_addr") | |
return inet_ntop(AF_INET, ffi.buffer(sin6_addr)[0:ffi.sizeof("struct in6_addr")]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment