Skip to content

Instantly share code, notes, and snippets.

@exarkun
Created March 31, 2022 19:30
Show Gist options
  • Save exarkun/1e413822a925f5f366e3a8f8e5345bee to your computer and use it in GitHub Desktop.
Save exarkun/1e413822a925f5f366e3a8f8e5345bee to your computer and use it in GitHub Desktop.
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