From a84c4dc1f46260bbdeadb0e5f6511fca46f52205 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 7 Aug 2025 16:35:42 +0800 Subject: [PATCH] Netif: refactor API for dual-stack route detection Unifies IPv4 and IPv6 default route queries under a shared result structure and per-family functions. Improves clarity and extensibility by centralizing route logic, streamlining detection of preferred interfaces, and updating all consumers to use the new API. Prepares for more robust multi-protocol network information handling. --- src/common/netif/netif.c | 40 +-- src/common/netif/netif.h | 29 +- src/common/netif/netif_bsd.c | 81 ++++- src/common/netif/netif_haiku.c | 17 +- src/common/netif/netif_linux.c | 374 ++++++++++++++++-------- src/common/netif/netif_obsd.c | 54 +++- src/common/netif/netif_windows.c | 72 ++++- src/detection/dns/dns_windows.c | 2 +- src/detection/localip/localip_linux.c | 111 ++++++- src/detection/localip/localip_windows.c | 2 +- src/detection/netio/netio_apple.c | 4 +- src/detection/netio/netio_bsd.c | 2 +- src/detection/netio/netio_haiku.cpp | 2 +- src/detection/netio/netio_linux.c | 2 +- src/detection/netio/netio_sunos.c | 2 +- src/detection/netio/netio_windows.c | 2 +- 16 files changed, 585 insertions(+), 211 deletions(-) diff --git a/src/common/netif/netif.c b/src/common/netif/netif.c index 17b8726a4..52792a9f9 100644 --- a/src/common/netif/netif.c +++ b/src/common/netif/netif.c @@ -2,39 +2,23 @@ #ifndef _WIN32 #include -#else - #include - #include + #include #endif -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr); -enum { IF_INDEX_UNINITIALIZED = (uint32_t) -1, IF_INDEX_INVALID = (uint32_t) -2 }; -static uint32_t ifIndex = IF_INDEX_UNINITIALIZED; -static char ifName[IF_NAMESIZE + 1]; -static uint32_t preferredSourceAddr = 0; - -static inline void init() +const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void) { - if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED) { - if (!ffNetifGetDefaultRouteImpl(ifName, &ifIndex, &preferredSourceAddr)) - ifIndex = (uint32_t) IF_INDEX_INVALID; + static FFNetifDefaultRouteResult result; + if (result.status == FF_NETIF_UNINITIALIZED) { + result.status = ffNetifGetDefaultRouteImplV4(&result) ? FF_NETIF_OK : FF_NETIF_INVALID; } + return &result; } -const char* ffNetifGetDefaultRouteIfName() +const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void) { - init(); - return ifName; -} - -uint32_t ffNetifGetDefaultRouteIfIndex() -{ - init(); - return ifIndex; -} - -uint32_t ffNetifGetDefaultRoutePreferredSourceAddr() -{ - init(); - return preferredSourceAddr; + static FFNetifDefaultRouteResult result; + if (result.status == FF_NETIF_UNINITIALIZED) { + result.status = ffNetifGetDefaultRouteImplV6(&result) ? FF_NETIF_OK : FF_NETIF_INVALID; + } + return &result; } diff --git a/src/common/netif/netif.h b/src/common/netif/netif.h index 1d7bd1dd2..99a1a69a0 100644 --- a/src/common/netif/netif.h +++ b/src/common/netif/netif.h @@ -2,6 +2,29 @@ #include "fastfetch.h" -const char* ffNetifGetDefaultRouteIfName(); -uint32_t ffNetifGetDefaultRouteIfIndex(); -uint32_t ffNetifGetDefaultRoutePreferredSourceAddr(); +#ifndef _WIN32 + #include + #include +#endif + +typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus { + FF_NETIF_UNINITIALIZED, + FF_NETIF_INVALID, + FF_NETIF_OK +} FFNetifDefaultRouteResultStatus; + +typedef struct FFNetifDefaultRouteResult { + uint32_t ifIndex; + + #ifndef _WIN32 + char ifName[IF_NAMESIZE + 1]; + uint32_t preferredSourceAddrV4; + #endif + enum FFNetifDefaultRouteResultStatus status; +} FFNetifDefaultRouteResult; + +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result); +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result); + +const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void); +const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void); diff --git a/src/common/netif/netif_bsd.c b/src/common/netif/netif_bsd.c index 52c4750ae..a0cc4e521 100644 --- a/src/common/netif/netif_bsd.c +++ b/src/common/netif/netif_bsd.c @@ -42,11 +42,8 @@ get_rt_address(struct rt_msghdr *rtm, int desired) return NULL; } -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { - if (preferredSourceAddr) - *preferredSourceAddr = 0; - //https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104 FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET); @@ -98,14 +95,80 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, ) { assert(sdl->sdl_nlen <= IF_NAMESIZE); - memcpy(iface, sdl->sdl_data, sdl->sdl_nlen); - iface[sdl->sdl_nlen] = '\0'; - *ifIndex = sdl->sdl_index; + memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen); + result->ifName[sdl->sdl_nlen] = '\0'; + result->ifIndex = sdl->sdl_index; // Get the preferred source address struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(&rtmsg.hdr, RTA_IFA); - if (preferredSourceAddr && src && src->sin_family == AF_INET) - *preferredSourceAddr = src->sin_addr.s_addr; + if (src && src->sin_family == AF_INET) + result->preferredSourceAddrV4 = src->sin_addr.s_addr; + + return true; + } + return false; + } + } + + return false; +} + +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) +{ + //https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104 + + FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET6); + if (pfRoute < 0) + return false; + + { + struct timeval timeout = {1, 0}; + setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)); + } + + int pid = getpid(); + + struct { + struct rt_msghdr hdr; + struct sockaddr_in6 dst; + uint8_t data[512]; + } rtmsg = { + .hdr = { + .rtm_type = RTM_GET, + .rtm_flags = RTF_UP | RTF_GATEWAY, + .rtm_version = RTM_VERSION, + .rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA, + .rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst), + .rtm_pid = pid, + .rtm_seq = 1, + }, + .dst = { + .sin6_family = AF_INET6, + #ifndef __sun + .sin6_len = sizeof(rtmsg.dst), + #endif + }, + }; + + if (write(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen) != rtmsg.hdr.rtm_msglen) + return false; + + while (read(pfRoute, &rtmsg, sizeof(rtmsg)) > 0) + { + if (rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid) + { + struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP); + if (sdl + #ifndef __sun + && sdl->sdl_len + #endif + ) + { + assert(sdl->sdl_nlen <= IF_NAMESIZE); + memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen); + result->ifName[sdl->sdl_nlen] = '\0'; + result->ifIndex = sdl->sdl_index; return true; } diff --git a/src/common/netif/netif_haiku.c b/src/common/netif/netif_haiku.c index cb7401ab6..914db83e2 100644 --- a/src/common/netif/netif_haiku.c +++ b/src/common/netif/netif_haiku.c @@ -11,12 +11,8 @@ // loosely based on Haiku's src/bin/network/route/route.cpp -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { - if (preferredSourceAddr) - *preferredSourceAddr = 0; - - // TODO: AF_INET6 FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET); if (pfRoute < 0) return false; @@ -45,8 +41,9 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, while (interface < end) { if (interface->ifr_route.flags & RTF_DEFAULT) { - strlcpy(iface, interface->ifr_name, IF_NAMESIZE); - *ifIndex = if_nametoindex(interface->ifr_name); + strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE); + result->ifIndex = if_nametoindex(interface->ifr_name); + // TODO: Get the preferred source address return true; } @@ -64,3 +61,9 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, return false; } + +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) +{ + // TODO: AF_INET6 + return false; +} diff --git a/src/common/netif/netif_linux.c b/src/common/netif/netif_linux.c index 6a484e789..cef654d6b 100644 --- a/src/common/netif/netif_linux.c +++ b/src/common/netif/netif_linux.c @@ -9,88 +9,82 @@ #define FF_STR_INDIR(x) #x #define FF_STR(x) FF_STR_INDIR(x) -struct req_t { - struct nlmsghdr nlh; - struct rtmsg rtm; - struct rtattr rta; - uint32_t table; -}; - -struct Route4Entry { - uint32_t dest; - uint32_t gateway; - uint32_t src; - uint8_t prefix_length; - uint32_t metric; - uint32_t ifindex; -}; - -static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (sock_fd < 0) return false; + unsigned pid = (unsigned) getpid(); + // Bind socket - struct sockaddr_nl addr; - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; // Let kernel assign PID - addr.nl_groups = 0; + struct sockaddr_nl addr = { + .nl_family = AF_NETLINK, + .nl_pid = pid, + .nl_groups = 0, // No multicast groups + }; if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { return false; } - struct req_t req; - memset(&req, 0, sizeof(req)); + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + struct rtattr rta; + uint32_t table; + } req = { + // Netlink message header + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = RTM_GETROUTE, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_seq = 1, + .nlmsg_pid = pid, + }, + // Route message + .rtm = { + .rtm_family = AF_INET, + .rtm_dst_len = 0, // Match all destinations + .rtm_src_len = 0, // Match all sources + .rtm_tos = 0, + .rtm_table = RT_TABLE_UNSPEC, + .rtm_protocol = RTPROT_UNSPEC, + .rtm_scope = RT_SCOPE_UNIVERSE, + .rtm_type = RTN_UNSPEC, + .rtm_flags = 0, + }, + // Route attribute for main table + .rta = { + .rta_len = RTA_LENGTH(sizeof(uint32_t)), + .rta_type = RTA_TABLE, + }, + .table = RT_TABLE_MAIN, + }; - // Netlink message header - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = RTM_GETROUTE; - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nlh.nlmsg_seq = 0; - req.nlh.nlmsg_pid = 0; - - // Route message - req.rtm.rtm_family = AF_INET; - req.rtm.rtm_dst_len = 0; - req.rtm.rtm_src_len = 0; - req.rtm.rtm_tos = 0; - req.rtm.rtm_table = RT_TABLE_UNSPEC; - req.rtm.rtm_protocol = RTPROT_UNSPEC; - req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; - req.rtm.rtm_type = RTN_UNSPEC; - req.rtm.rtm_flags = 0; - - // Route attribute for main table - req.rta.rta_len = RTA_LENGTH(sizeof(uint32_t)); - req.rta.rta_type = RTA_TABLE; - req.table = RT_TABLE_MAIN; - - struct sockaddr_nl dest_addr; - memset(&dest_addr, 0, sizeof(dest_addr)); - dest_addr.nl_family = AF_NETLINK; - dest_addr.nl_pid = 0; - dest_addr.nl_groups = 0; + struct sockaddr_nl dest_addr = { + .nl_family = AF_NETLINK, + .nl_pid = 0, // Kernel + .nl_groups = 0, // No multicast groups + }; ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0, - (struct sockaddr*)&dest_addr, sizeof(dest_addr)); + (struct sockaddr*)&dest_addr, sizeof(dest_addr)); if (sent != sizeof(req)) { return false; } - struct sockaddr_nl src_addr; + struct sockaddr_nl src_addr = {}; socklen_t src_addr_len = sizeof(src_addr); - struct iovec iov = {NULL, 0}; - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &src_addr; - msg.msg_namelen = sizeof(src_addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + struct iovec iov = {}; + struct msghdr msg = { + .msg_name = &src_addr, + .msg_namelen = sizeof(src_addr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; ssize_t peek_size = recvmsg(sock_fd, &msg, MSG_PEEK | MSG_TRUNC); if (peek_size < 0) { @@ -100,18 +94,23 @@ static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, FF_AUTO_FREE uint8_t* buffer = malloc((size_t)peek_size); ssize_t received = recvfrom(sock_fd, buffer, (size_t)peek_size, 0, - (struct sockaddr*)&src_addr, &src_addr_len); + (struct sockaddr*)&src_addr, &src_addr_len); if (received != peek_size) { return false; } - struct Route4Entry best_gw; - memset(&best_gw, 0, sizeof(best_gw)); + struct { + uint32_t metric; + uint32_t ifindex; + uint32_t prefsrc; + } entry; + uint32_t minMetric = UINT32_MAX; for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer; NLMSG_OK(nlh, received); nlh = NLMSG_NEXT(nlh, received)) { - + if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid) + continue; if (nlh->nlmsg_type == NLMSG_DONE) break; @@ -122,83 +121,222 @@ static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, if (rtm->rtm_family != AF_INET) continue; - struct Route4Entry entry; - memset(&entry, 0, sizeof(struct Route4Entry)); - entry.prefix_length = rtm->rtm_dst_len; + if (rtm->rtm_dst_len != 0) + continue; + + entry = (__typeof__(entry)) { .metric = UINT32_MAX }; // Parse route attributes size_t rtm_len = RTM_PAYLOAD(nlh); for (struct rtattr* rta = RTM_RTA(rtm); RTA_OK(rta, rtm_len); - rta = RTA_NEXT(rta, rtm_len)) { + rta = RTA_NEXT(rta, rtm_len)) + { + if (RTA_PAYLOAD(rta) < sizeof(uint32_t)) + continue; // Skip invalid attributes + uint32_t rta_data = *(uint32_t*) RTA_DATA(rta); switch (rta->rta_type) { case RTA_DST: - entry.dest = *(uint32_t*)RTA_DATA(rta); - break; - case RTA_GATEWAY: - entry.gateway = *(uint32_t*)RTA_DATA(rta); - break; - case RTA_PREFSRC: - entry.src = *(uint32_t*)RTA_DATA(rta); - break; - case RTA_PRIORITY: - entry.metric = *(uint32_t*)RTA_DATA(rta); + if (rta_data != 0) goto next; break; case RTA_OIF: - entry.ifindex = *(uint32_t*)RTA_DATA(rta); + entry.ifindex = rta_data; + break; + case RTA_GATEWAY: + if (rta_data == 0) goto next; + break; + case RTA_PRIORITY: + if (rta_data >= minMetric) goto next; + entry.metric = rta_data; + break; + case RTA_PREFSRC: + entry.prefsrc = rta_data; break; } } - if (entry.gateway == 0 || entry.dest != 0 || entry.prefix_length != 0) + if (entry.metric >= minMetric) + { + next: + continue; + } + minMetric = entry.metric; + result->ifIndex = entry.ifindex; + result->preferredSourceAddrV4 = entry.prefsrc; + } + + if (minMetric < UINT32_MAX) + { + if_indextoname(result->ifIndex, result->ifName); + return true; + } + return false; +} + +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) +{ + FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + if (sock_fd < 0) + return false; + + unsigned pid = (unsigned) getpid(); + + // Bind socket + struct sockaddr_nl addr = { + .nl_family = AF_NETLINK, + .nl_pid = pid, + .nl_groups = 0, // No multicast groups + }; + + if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + return false; + } + + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + struct rtattr rta; + uint32_t table; + } req = { + // Netlink message header + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = RTM_GETROUTE, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_seq = 1, + .nlmsg_pid = pid, + }, + // Route message + .rtm = { + .rtm_family = AF_INET6, // IPv6 instead of IPv4 + .rtm_dst_len = 0, // Match all destinations + .rtm_src_len = 0, // Match all sources + .rtm_tos = 0, + .rtm_table = RT_TABLE_UNSPEC, + .rtm_protocol = RTPROT_UNSPEC, + .rtm_scope = RT_SCOPE_UNIVERSE, + .rtm_type = RTN_UNSPEC, + .rtm_flags = 0, + }, + // Route attribute for main table + .rta = { + .rta_len = RTA_LENGTH(sizeof(uint32_t)), + .rta_type = RTA_TABLE, + }, + .table = RT_TABLE_MAIN, + }; + + struct sockaddr_nl dest_addr = { + .nl_family = AF_NETLINK, + .nl_pid = 0, // Kernel + .nl_groups = 0, // No multicast groups + }; + + ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0, + (struct sockaddr*)&dest_addr, sizeof(dest_addr)); + + if (sent != sizeof(req)) { + return false; + } + + struct sockaddr_nl src_addr = {}; + socklen_t src_addr_len = sizeof(src_addr); + + struct iovec iov = {}; + struct msghdr msg = { + .msg_name = &src_addr, + .msg_namelen = sizeof(src_addr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + ssize_t peek_size = recvmsg(sock_fd, &msg, MSG_PEEK | MSG_TRUNC); + if (peek_size < 0) { + return false; + } + + FF_AUTO_FREE uint8_t* buffer = malloc((size_t)peek_size); + + ssize_t received = recvfrom(sock_fd, buffer, (size_t)peek_size, 0, + (struct sockaddr*)&src_addr, &src_addr_len); + if (received != peek_size) { + return false; + } + + struct { + uint32_t metric; + uint32_t ifindex; + } entry; + uint32_t minMetric = UINT32_MAX; + + for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer; + NLMSG_OK(nlh, received); + nlh = NLMSG_NEXT(nlh, received)) { + if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid) + continue; + if (nlh->nlmsg_type == NLMSG_DONE) + break; + + if (nlh->nlmsg_type != RTM_NEWROUTE) continue; - if (best_gw.gateway == 0 || entry.metric < best_gw.metric) { - memcpy(&best_gw, &entry, sizeof(struct Route4Entry)); - } - } + struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh); + if (rtm->rtm_family != AF_INET6) + continue; - if (best_gw.gateway != 0) { - if (ifIndex) { - *ifIndex = best_gw.ifindex; - } - if (iface) { - if (if_indextoname(best_gw.ifindex, iface) == NULL) { - iface[0] = '\0'; + if (rtm->rtm_dst_len != 0) + continue; + + entry = (__typeof__(entry)) { .metric = UINT32_MAX }; + + // Parse route attributes + size_t rtm_len = RTM_PAYLOAD(nlh); + for (struct rtattr* rta = RTM_RTA(rtm); + RTA_OK(rta, rtm_len); + rta = RTA_NEXT(rta, rtm_len)) + { + switch (rta->rta_type) { + case RTA_DST: + if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) { + struct in6_addr* dst = (struct in6_addr*) RTA_DATA(rta); + if (!IN6_IS_ADDR_UNSPECIFIED(dst)) goto next; + } + break; + case RTA_OIF: + if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) { + entry.ifindex = *(uint32_t*) RTA_DATA(rta); + } + break; + case RTA_GATEWAY: + if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) { + struct in6_addr* gw = (struct in6_addr*) RTA_DATA(rta); + if (IN6_IS_ADDR_UNSPECIFIED(gw)) goto next; + } + break; + case RTA_PRIORITY: + if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) { + uint32_t metric = *(uint32_t*) RTA_DATA(rta); + if (metric >= minMetric) goto next; + entry.metric = metric; + } + break; } } - if (preferredSourceAddr) { - *preferredSourceAddr = best_gw.src; + + if (entry.metric >= minMetric) + { + next: + continue; } - return true; + minMetric = entry.metric; + result->ifIndex = entry.ifindex; } - - iface[0] = '\0'; - return false; -} -static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex) -{ - FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/ipv6_route", "r"); - if (!netRoute) return false; - - uint32_t prefixLen; - //destination, dest_prefix_len, source, src_prefix_len, next hop, metric, ref counter, use counter, flags, iface - while (fscanf(netRoute, "%*s %x %*s %*s %*s %*s %*s %*s %*s %" FF_STR(IF_NAMESIZE) "s", &prefixLen, iface) == 2) + if (minMetric < UINT32_MAX) { - if (prefixLen != 0) continue; - *ifIndex = if_nametoindex(iface); + if_indextoname(result->ifIndex, result->ifName); return true; } - iface[0] = '\0'; return false; } - -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) -{ - if (getDefaultRouteIPv4(iface, ifIndex, preferredSourceAddr)) - return true; - - return getDefaultRouteIPv6(iface, ifIndex); -} diff --git a/src/common/netif/netif_obsd.c b/src/common/netif/netif_obsd.c index c2224e16e..4c419a608 100644 --- a/src/common/netif/netif_obsd.c +++ b/src/common/netif/netif_obsd.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -35,11 +36,8 @@ get_rt_address(struct rt_msghdr *rtm, int desired) return NULL; } -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { - if (preferredSourceAddr) - *preferredSourceAddr = 0; - int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY}; size_t needed; @@ -64,14 +62,52 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, if (sdl->sdl_family == AF_LINK) { assert(sdl->sdl_nlen <= IF_NAMESIZE); - memcpy(iface, sdl->sdl_data, sdl->sdl_nlen); - iface[sdl->sdl_nlen] = '\0'; - *ifIndex = sdl->sdl_index; + memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen); + result->ifName[sdl->sdl_nlen] = '\0'; + result->ifIndex = sdl->sdl_index; // Get the preferred source address struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(rtm, RTA_IFA); - if (preferredSourceAddr && src && src->sin_family == AF_INET) - *preferredSourceAddr = src->sin_addr.s_addr; + if (src && src->sin_family == AF_INET) + result->preferredSourceAddrV4 = src->sin_addr.s_addr; + + return true; + } + } + } + + return false; +} + +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) +{ + int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY}; + size_t needed; + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return false; + + FF_AUTO_FREE char* buf = malloc(needed); + + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + return false; + + char* lim = buf + needed; + struct rt_msghdr* rtm; + for (char* next = buf; next < lim; next += rtm->rtm_msglen) + { + rtm = (struct rt_msghdr *)next; + struct sockaddr* sa = (struct sockaddr *)(rtm + 1); + + if ((rtm->rtm_flags & RTF_GATEWAY) && (sa->sa_family == AF_INET6)) + { + struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP); + if (sdl && sdl->sdl_family == AF_LINK) + { + assert(sdl->sdl_nlen <= IF_NAMESIZE); + memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen); + result->ifName[sdl->sdl_nlen] = '\0'; + result->ifIndex = sdl->sdl_index; return true; } diff --git a/src/common/netif/netif_windows.c b/src/common/netif/netif_windows.c index 275c7b62e..4fa7144b3 100644 --- a/src/common/netif/netif_windows.c +++ b/src/common/netif/netif_windows.c @@ -4,11 +4,8 @@ #include // AF_INET6, IN6_IS_ADDR_UNSPECIFIED #include -bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr) +bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { - if (preferredSourceAddr) - *preferredSourceAddr = 0; - PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL; if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) @@ -21,20 +18,17 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, { MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i]; - if ((row->DestinationPrefix.PrefixLength == 0) && - ((row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET && - row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) || - (row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 && - IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr)))) + if (row->DestinationPrefix.PrefixLength == 0 && + row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET && + row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) { MIB_IF_ROW2 ifRow = { .InterfaceIndex = row->InterfaceIndex, }; - if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && - ifRow.OperStatus == IfOperStatusUp) + if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp) { MIB_IPINTERFACE_ROW ipInterfaceRow = { - .Family = (row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET) ? AF_INET : AF_INET6, + .Family = AF_INET, .InterfaceIndex = row->InterfaceIndex, }; @@ -46,9 +40,57 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, if (realMetric < smallestMetric) { smallestMetric = realMetric; - *ifIndex = row->InterfaceIndex; - if (WideCharToMultiByte(CP_UTF8, 0, ifRow.Alias, -1, iface, IF_NAMESIZE, NULL, NULL) > 0) - iface[IF_NAMESIZE] = '\0'; + result->ifIndex = row->InterfaceIndex; + foundDefault = true; + break; + } + } + } + } + + FreeMibTable(pIpForwardTable); + + return foundDefault; +} + + +bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) +{ + PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL; + + if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) + return false; + + bool foundDefault = false; + uint32_t smallestMetric = UINT32_MAX; + + for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i) + { + MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i]; + + if (row->DestinationPrefix.PrefixLength == 0 && + row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr)) + { + MIB_IF_ROW2 ifRow = { + .InterfaceIndex = row->InterfaceIndex, + }; + if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp) + { + MIB_IPINTERFACE_ROW ipInterfaceRow = { + .Family = AF_INET6, + .InterfaceIndex = row->InterfaceIndex, + }; + + uint32_t realMetric = row->Metric /* Metric offset */; + + if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow))) + realMetric += ipInterfaceRow.Metric /* Interface metric */; + + if (realMetric < smallestMetric) + { + smallestMetric = realMetric; + result->ifIndex = row->InterfaceIndex; foundDefault = true; } } diff --git a/src/detection/dns/dns_windows.c b/src/detection/dns/dns_windows.c index 55cda9e4f..48615117f 100644 --- a/src/detection/dns/dns_windows.c +++ b/src/detection/dns/dns_windows.c @@ -37,7 +37,7 @@ const char* ffDetectDNS(FFDNSOptions* options, FFlist* results) return "GetAdaptersAddresses() failed"; } - uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex(); + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex; // Iterate through all of the adapters for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next) { diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c index ac8ead7dd..318c3fa92 100644 --- a/src/detection/localip/localip_linux.c +++ b/src/detection/localip/localip_linux.c @@ -11,11 +11,17 @@ #include #include #include +#include #ifdef __linux__ #include #include #include +#include +#endif + +#if __has_include() + #include #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined(__HAIKU__) @@ -88,6 +94,7 @@ static void addNewIp(FFlist* list, const char* name, const char* addr, int type, { if (!ffStrbufEqualS(&temp->name, name)) continue; ip = temp; + if (defaultRoute) ip->defaultRoute = true; break; } if (!ip) @@ -129,28 +136,87 @@ static void addNewIp(FFlist* list, const char* name, const char* addr, int type, } } +static bool isIPv6AddressPreferred(const char* ifname, struct sockaddr_in6* addr) +{ +#ifndef IN6_IS_ADDR_GLOBAL +#define IN6_IS_ADDR_GLOBAL(a) \ + ((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000)) +#endif + if (!IN6_IS_ADDR_GLOBAL(&addr->sin6_addr)) + return false; + +#ifdef SIOCGIFAFLAG_IN6 + static int sockfd = 0; + if (sockfd == 0) sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd < 0) return true; // Give up + + struct in6_ifreq ifr6 = {}; + ffStrCopy(ifr6.ifr_name, ifname, IFNAMSIZ); + ifr6.ifr_addr = *addr; + + if (ioctl(sockfd, SIOCGIFAFLAG_IN6, &ifr6) != 0) + return true; + + return !(ifr6.ifr_flags & IN6_IFF_DEPRECATED) && !(ifr6.ifr_flags & IN6_IFF_TEMPORARY); +#elif __linux__ + FF_UNUSED(ifname); + + static FFlist addresses = {}; + if (addresses.elementSize == 0) + { + ffListInit(&addresses, sizeof(struct in6_addr)); + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + if (!ffReadFileBuffer("/proc/net/if_inet6", &buffer)) + return true; + + char* line = NULL; + size_t len = 0; + while (ffStrbufGetline(&line, &len, &buffer)) + { + struct in6_addr* entry = (struct in6_addr*) ffListAdd(&addresses); + uint8_t flags; + if (sscanf(line, "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 " %*s %*s %*s %" SCNx8 " %*s", + &entry->s6_addr[0], &entry->s6_addr[1], &entry->s6_addr[2], &entry->s6_addr[3], + &entry->s6_addr[4], &entry->s6_addr[5], &entry->s6_addr[6], &entry->s6_addr[7], + &entry->s6_addr[8], &entry->s6_addr[9], &entry->s6_addr[10], &entry->s6_addr[11], + &entry->s6_addr[12], &entry->s6_addr[13], &entry->s6_addr[14], &entry->s6_addr[15], + &flags) != 17 || + !IN6_IS_ADDR_GLOBAL(entry) || + (flags & IFA_F_DEPRECATED) || + (flags & IFA_F_TEMPORARY) + ) + --addresses.length; + } + } + if (addresses.capacity == 0) return true; // Give up + + FF_LIST_FOR_EACH(struct in6_addr, entry, addresses) + { + if (memcmp(&addr->sin6_addr, entry, sizeof(struct in6_addr)) == 0) + return true; + } + return false; +#else + return true; +#endif +} + const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) { struct ifaddrs* ifAddrStruct = NULL; if(getifaddrs(&ifAddrStruct) < 0) return "getifaddrs(&ifAddrStruct) failed"; - const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName(); - const uint32_t preferredSourceAddr = ffNetifGetDefaultRoutePreferredSourceAddr(); - for (struct ifaddrs* ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; + #ifdef IFF_RUNNING if (!(ifa->ifa_flags & IFF_RUNNING)) continue; #endif - bool isDefaultRouteIf = ffStrEquals(defaultRouteIfName, ifa->ifa_name); - if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRouteIf) - continue; - if ((ifa->ifa_flags & IFF_LOOPBACK) && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT)) continue; @@ -166,9 +232,20 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) struct sockaddr_in* ipv4 = (struct sockaddr_in*) ifa->ifa_addr; - bool isDefaultRoute = isDefaultRouteIf && (preferredSourceAddr == 0 || ipv4->sin_addr.s_addr == preferredSourceAddr); - if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute) - continue; + const FFNetifDefaultRouteResult* defaultRoute = ffNetifGetDefaultRouteV4(); + bool isDefaultRouteIf = ffStrEquals(defaultRoute->ifName, ifa->ifa_name); + if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) + { + if (!isDefaultRouteIf) + continue; + + if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)) + { + bool isPreferredSourceAddr = defaultRoute->preferredSourceAddrV4 == 0 || ipv4->sin_addr.s_addr == defaultRoute->preferredSourceAddrV4; + if (!isPreferredSourceAddr) + continue; + } + } char addressBuffer[INET_ADDRSTRLEN + 16]; inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN); @@ -184,14 +261,22 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } } - addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); + addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRouteIf, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); } else if (ifa->ifa_addr->sa_family == AF_INET6) { if (!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT)) continue; + const FFNetifDefaultRouteResult* defaultRoute = ffNetifGetDefaultRouteV6(); + bool isDefaultRouteIf = ffStrEquals(defaultRoute->ifName, ifa->ifa_name); + if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRouteIf) + continue; + struct sockaddr_in6* ipv6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) && !isIPv6AddressPreferred(ifa->ifa_name, ipv6)) + continue; + char addressBuffer[INET6_ADDRSTRLEN + 16]; inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN); @@ -221,7 +306,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = (uint8_t*) LLADDR((struct sockaddr_dl *)ifa->ifa_addr); snprintf(addressBuffer, ARRAY_SIZE(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRouteIf, flags, false); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, false, flags, false); } #else else if (ifa->ifa_addr->sa_family == AF_PACKET) @@ -233,7 +318,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = ((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr; snprintf(addressBuffer, ARRAY_SIZE(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRouteIf, flags, false); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, false, flags, false); } #endif } diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 45b1445b5..143326f83 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -90,7 +90,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) return "GetAdaptersAddresses() failed"; } - uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex(); + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex; // Iterate through all of the adapters for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next) diff --git a/src/detection/netio/netio_apple.c b/src/detection/netio/netio_apple.c index cd5106026..69f2667c9 100644 --- a/src/detection/netio/netio_apple.c +++ b/src/detection/netio/netio_apple.c @@ -11,7 +11,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) { int mib[] = {CTL_NET, PF_LINK, NETLINK_GENERIC, options->defaultRouteOnly ? IFMIB_IFDATA : IFMIB_IFALLDATA, - options->defaultRouteOnly ? (int) ffNetifGetDefaultRouteIfIndex() : 0, + options->defaultRouteOnly ? (int) ffNetifGetDefaultRouteV4()->ifIndex : 0, IFDATA_GENERAL}; size_t bufSize = 0; @@ -26,7 +26,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) size_t ifCount = bufSize / sizeof(struct ifmibdata); - const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName(); + const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName; for (size_t i = 0; i < ifCount; i++) { diff --git a/src/detection/netio/netio_bsd.c b/src/detection/netio/netio_bsd.c index 9044600e5..dcf9b709d 100644 --- a/src/detection/netio/netio_bsd.c +++ b/src/detection/netio/netio_bsd.c @@ -12,7 +12,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) { - uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex(); + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex; size_t bufSize = 0; if (sysctl((int[]) { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, (options->defaultRouteOnly ? (int) defaultRouteIfIndex : 0) }, 6, NULL, &bufSize, 0, 0) < 0) diff --git a/src/detection/netio/netio_haiku.cpp b/src/detection/netio/netio_haiku.cpp index e0c62ebf2..812d926f4 100644 --- a/src/detection/netio/netio_haiku.cpp +++ b/src/detection/netio/netio_haiku.cpp @@ -13,7 +13,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) BNetworkInterface interface; uint32 cookie = 0; - uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex(); + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex; while (roster.GetNextInterface(&cookie, interface) == B_OK) { diff --git a/src/detection/netio/netio_linux.c b/src/detection/netio/netio_linux.c index 2a28c10eb..651a612fa 100644 --- a/src/detection/netio/netio_linux.c +++ b/src/detection/netio/netio_linux.c @@ -53,7 +53,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); - const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName(); + const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName; if (options->defaultRouteOnly) { diff --git a/src/detection/netio/netio_sunos.c b/src/detection/netio/netio_sunos.c index e87222e83..b85e1f671 100644 --- a/src/detection/netio/netio_sunos.c +++ b/src/detection/netio/netio_sunos.c @@ -16,7 +16,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) if (!kc) return "kstat_open() failed"; - const char* defaultRoute = ffNetifGetDefaultRouteIfName(); + const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName; for (kstat_t* ks = kc->kc_chain; ks; ks = ks->ks_next) { diff --git a/src/detection/netio/netio_windows.c b/src/detection/netio/netio_windows.c index 1d3ab8fbe..56e5fc06d 100644 --- a/src/detection/netio/netio_windows.c +++ b/src/detection/netio/netio_windows.c @@ -37,7 +37,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) return "GetAdaptersAddresses() failed"; } - uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex(); + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex; // Iterate through all of the adapters for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)