from nativesockets import getAddrString from net import IpAddress, parseIpAddress, `$` from posix import SockAddr, AF_INET, AF_INET6 type NetworkInterface* = object ipAddress*: IpAddress netMask*: IpAddress name*: string index*: cint flags*: cuint NetworkInterfaceError* = object of CatchableError Ifaddrs {.importc: "struct ifaddrs", pure, final, header: "".} = object ifa_next: ptr Ifaddrs # Next item in list ifa_name: cstring # Name of interface ifa_flags: cuint # Flags from SIOCGIFFLAGS ifa_addr: ptr SockAddr # Address of interface ifa_netmask: ptr SockAddr # Netmask of interface ifa_ifu: ptr SockAddr # Broadcast / point-to-point address (we don't care about the union) ifa_data: pointer # Address-specific data proc getifaddrs(ifap: ptr ptr Ifaddrs): int {.header: "", importc: "getifaddrs".} proc freeifaddrs(ifap: ptr Ifaddrs): void {.header: "", importc: "freeifaddrs".} proc if_nametoindex(ifname: cstring): cuint {.header: "", importc: "if_nametoindex".} proc getNetworkInterface*(address: IpAddress): NetworkInterface = var interfaces: ptr Ifaddrs if getifaddrs(addr interfaces) != 0: raise newException(NetworkInterfaceError, "getifaddrs failed") var it = interfaces while it != nil: if it.ifa_addr != nil and (it.ifa_addr.sa_family.cint == AF_INET or it.ifa_addr.sa_family.cint == AF_INET6) and $address == it.ifa_addr.getAddrString(): result.ipAddress = address result.netMask = parseIpAddress(it.ifa_netmask.getAddrString()) result.name = $it.ifa_name result.index = if_nametoindex(result.name).cint result.flags = it.ifa_flags break it = it.ifa_next freeifaddrs(interfaces) if result.name == "": raise newException(NetworkInterfaceError, "interface for given IP address not found") if result.index <= 0: raise newException(NetworkInterfaceError, "cannot get interface index")