Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/common/netif/netif.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
#include <iphlpapi.h>
#endif

bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
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()
{
if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED && !ffNetifGetDefaultRouteImpl(ifName, &ifIndex))
ifIndex = (uint32_t) IF_INDEX_INVALID;
if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED) {
if (!ffNetifGetDefaultRouteImpl(ifName, &ifIndex, &preferredSourceAddr))
ifIndex = (uint32_t) IF_INDEX_INVALID;
}
}

const char* ffNetifGetDefaultRouteIfName()
Expand All @@ -29,3 +32,9 @@ uint32_t ffNetifGetDefaultRouteIfIndex()
init();
return ifIndex;
}

uint32_t ffNetifGetDefaultRoutePreferredSourceAddr()
{
init();
return preferredSourceAddr;
}
1 change: 1 addition & 0 deletions src/common/netif/netif.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

const char* ffNetifGetDefaultRouteIfName();
uint32_t ffNetifGetDefaultRouteIfIndex();
uint32_t ffNetifGetDefaultRoutePreferredSourceAddr();
16 changes: 14 additions & 2 deletions src/common/netif/netif_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ get_rt_address(struct rt_msghdr *rtm, int desired)
return NULL;
}

bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr)
{
#if defined(__OpenBSD__) || defined(__DragonFly__)
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
Expand Down Expand Up @@ -80,6 +80,12 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
iface[sdl->sdl_nlen] = '\0';
*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;

return true;
}
}
Expand Down Expand Up @@ -108,7 +114,7 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
.rtm_type = RTM_GET,
.rtm_flags = RTF_UP | RTF_GATEWAY,
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP,
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_seq = 1,
Expand Down Expand Up @@ -139,6 +145,12 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
iface[sdl->sdl_nlen] = '\0';
*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;

return true;
}
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/common/netif/netif_haiku.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

// loosely based on Haiku's src/bin/network/route/route.cpp

bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr)
{
// TODO: AF_INET6
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
Expand Down
175 changes: 162 additions & 13 deletions src/common/netif/netif_linux.c
Original file line number Diff line number Diff line change
@@ -1,27 +1,176 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"

#include <arpa/inet.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <stdio.h>

#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)

static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
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)
{
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/route", "r");
if (!netRoute) return false;
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sock_fd < 0)
return false;

// skip first line
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
// 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;

unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", iface, &destination) == 2)
{
if (destination != 0) continue;
*ifIndex = if_nametoindex(iface);
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
return false;
}

struct req_t req;
memset(&req, 0, sizeof(req));

// 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;

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 = {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;

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);

struct Route4Entry best_gw;
memset(&best_gw, 0, sizeof(best_gw));

for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
NLMSG_OK(nlh, received);
nlh = NLMSG_NEXT(nlh, received)) {

if (nlh->nlmsg_type == NLMSG_DONE)
break;

if (nlh->nlmsg_type != RTM_NEWROUTE)
continue;

struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
if (rtm->rtm_family != AF_INET)
continue;

struct Route4Entry entry;
memset(&entry, 0, sizeof(struct Route4Entry));
entry.prefix_length = rtm->rtm_dst_len;

// Parse route attributes
uint64_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:
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);
break;
case RTA_OIF:
entry.ifindex = *(uint32_t*)RTA_DATA(rta);
break;
}
}

if (entry.gateway == 0 || entry.dest != 0 || entry.prefix_length != 0)
continue;

if (best_gw.gateway == 0 || entry.metric < best_gw.metric) {
memcpy(&best_gw, &entry, sizeof(struct Route4Entry));
}
}

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 (preferredSourceAddr) {
*preferredSourceAddr = best_gw.src;
}
return true;
}

iface[0] = '\0';
return false;
}
Expand All @@ -43,9 +192,9 @@ static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
return false;
}

bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr)
{
if (getDefaultRouteIPv4(iface, ifIndex))
if (getDefaultRouteIPv4(iface, ifIndex, preferredSourceAddr))
return true;

return getDefaultRouteIPv6(iface, ifIndex);
Expand Down
2 changes: 1 addition & 1 deletion src/common/netif/netif_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
#include <iphlpapi.h>

bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex, uint32_t* preferredSourceAddr)
{
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;

Expand Down
16 changes: 11 additions & 5 deletions src/detection/localip/localip_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
return "getifaddrs(&ifAddrStruct) failed";

const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
const uint32_t preferredSourceAddr = ffNetifGetDefaultRoutePreferredSourceAddr();

for (struct ifaddrs* ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next)
{
Expand All @@ -146,8 +147,8 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;
#endif

bool isDefaultRoute = ffStrEquals(defaultRouteIfName, ifa->ifa_name);
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
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))
Expand All @@ -164,6 +165,11 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;

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;

char addressBuffer[INET_ADDRSTRLEN + 16];
inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN);

Expand Down Expand Up @@ -203,7 +209,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
}
}

addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT));
addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRouteIf, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT));
}
#if __FreeBSD__ || __OpenBSD__ || __APPLE__ || __NetBSD__ || __HAIKU__
else if (ifa->ifa_addr->sa_family == AF_LINK)
Expand All @@ -215,7 +221,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, isDefaultRoute, flags, false);
addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRouteIf, flags, false);
}
#else
else if (ifa->ifa_addr->sa_family == AF_PACKET)
Expand All @@ -227,7 +233,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, isDefaultRoute, flags, false);
addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRouteIf, flags, false);
}
#endif
}
Expand Down
Loading