Skip to content

Commit 6356f9d

Browse files
committed
Netif (Linux): improves default route detection and error handling
Ref: #1902
1 parent 597c6f3 commit 6356f9d

File tree

1 file changed

+62
-61
lines changed

1 file changed

+62
-61
lines changed

src/common/netif/netif_linux.c

Lines changed: 62 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@
77
#include <linux/rtnetlink.h>
88
#include <net/if.h>
99

10-
#define FF_STR_INDIR(x) #x
11-
#define FF_STR(x) FF_STR_INDIR(x)
12-
1310
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
1411
{
1512
FF_DEBUG("Starting IPv4 default route detection");
1613

1714
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
1815
if (sock_fd < 0)
1916
{
20-
FF_DEBUG("Failed to create netlink socket: errno=%d", errno);
17+
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
2118
return false;
2219
}
2320
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
@@ -28,17 +25,17 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
2825
// Bind socket
2926
struct sockaddr_nl addr = {
3027
.nl_family = AF_NETLINK,
31-
.nl_pid = pid,
28+
.nl_pid = 0, // Let kernel choose PID
3229
.nl_groups = 0, // No multicast groups
3330
};
3431

3532
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
36-
FF_DEBUG("Failed to bind socket: errno=%d", errno);
33+
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
3734
return false;
3835
}
3936
FF_DEBUG("Successfully bound socket");
4037

41-
struct {
38+
struct __attribute__((__packed__)) {
4239
struct nlmsghdr nlh;
4340
struct rtmsg rtm;
4441
struct rtattr rta;
@@ -90,27 +87,18 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
9087
struct sockaddr_nl src_addr = {};
9188
socklen_t src_addr_len = sizeof(src_addr);
9289

93-
struct iovec iov = {};
94-
struct msghdr msg = {
95-
.msg_name = &src_addr,
96-
.msg_namelen = sizeof(src_addr),
97-
.msg_iov = &iov,
98-
.msg_iovlen = 1,
99-
};
90+
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
91+
92+
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
93+
(struct sockaddr*)&src_addr, &src_addr_len);
10094

101-
ssize_t peek_size = recvmsg(sock_fd, &msg, MSG_PEEK | MSG_TRUNC);
102-
if (peek_size < 0) {
103-
FF_DEBUG("Failed to peek message size: errno=%d", errno);
95+
if (received < 0) {
96+
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
10497
return false;
10598
}
106-
FF_DEBUG("Message size: %zd bytes", peek_size);
107-
108-
FF_AUTO_FREE uint8_t* buffer = malloc((size_t)peek_size);
10999

110-
ssize_t received = recvfrom(sock_fd, buffer, (size_t)peek_size, 0,
111-
(struct sockaddr*)&src_addr, &src_addr_len);
112-
if (received != peek_size) {
113-
FF_DEBUG("Failed to receive complete message: received=%zd, expected=%zd", received, peek_size);
100+
if (received >= (ssize_t)sizeof(buffer)) {
101+
FF_DEBUG("Failed to receive complete message (possible truncation)");
114102
return false;
115103
}
116104
FF_DEBUG("Received netlink response: %zd bytes", received);
@@ -134,6 +122,12 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
134122
break;
135123
}
136124

125+
if (nlh->nlmsg_type == NLMSG_ERROR) {
126+
struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlh);
127+
FF_DEBUG("Netlink reports error: %s", strerror(-err->error));
128+
continue;
129+
}
130+
137131
if (nlh->nlmsg_type != RTM_NEWROUTE)
138132
continue;
139133

@@ -146,7 +140,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
146140
continue;
147141

148142
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
149-
entry = (__typeof__(entry)) { .metric = UINT32_MAX };
143+
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
150144

151145
// Parse route attributes
152146
size_t rtm_len = RTM_PAYLOAD(nlh);
@@ -160,21 +154,20 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
160154
uint32_t rta_data = *(uint32_t*) RTA_DATA(rta);
161155
switch (rta->rta_type) {
162156
case RTA_DST:
163-
FF_DEBUG("Found destination: %s", inet_ntoa(*(struct in_addr*)&rta_data));
164-
if (rta_data != 0) goto next;
165-
break;
157+
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) { .s_addr = rta_data }), rtm->rtm_dst_len);
158+
goto next;
166159
case RTA_OIF:
167160
entry.ifindex = rta_data;
168161
FF_DEBUG("Found interface index: %u", entry.ifindex);
169162
break;
170163
case RTA_GATEWAY:
171-
if (rta_data == 0) goto next;
172164
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*)&rta_data));
165+
if (rta_data == 0) goto next;
173166
break;
174167
case RTA_PRIORITY:
168+
FF_DEBUG("Found metric: %u", rta_data);
175169
if (rta_data >= minMetric) goto next;
176170
entry.metric = rta_data;
177-
FF_DEBUG("Found metric: %u", entry.metric);
178171
break;
179172
case RTA_PREFSRC:
180173
entry.prefsrc = rta_data;
@@ -183,15 +176,21 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
183176
}
184177
}
185178

186-
if (entry.metric >= minMetric)
179+
if (entry.ifindex == 0 || entry.metric >= minMetric)
187180
{
188181
next:
182+
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
189183
continue;
190184
}
191185
minMetric = entry.metric;
192186
result->ifIndex = entry.ifindex;
193-
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
194-
// result->preferredSourceAddrV4 = entry.prefsrc;
187+
FF_DEBUG("Updated best route: ifindex=%u, metric=%u, prefsrc=%x", entry.ifindex, entry.metric, entry.prefsrc);
188+
result->preferredSourceAddrV4 = entry.prefsrc;
189+
if (minMetric == 0)
190+
{
191+
FF_DEBUG("Found zero metric route, stopping further processing");
192+
break; // Stop processing if we found a zero metric route
193+
}
195194
}
196195

197196
if (minMetric < UINT32_MAX)
@@ -211,7 +210,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
211210
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
212211
if (sock_fd < 0)
213212
{
214-
FF_DEBUG("Failed to create netlink socket: errno=%d", errno);
213+
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
215214
return false;
216215
}
217216
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
@@ -222,17 +221,17 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
222221
// Bind socket
223222
struct sockaddr_nl addr = {
224223
.nl_family = AF_NETLINK,
225-
.nl_pid = pid,
224+
.nl_pid = 0, // Let kernel choose PID
226225
.nl_groups = 0, // No multicast groups
227226
};
228227

229228
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
230-
FF_DEBUG("Failed to bind socket: errno=%d", errno);
229+
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
231230
return false;
232231
}
233232
FF_DEBUG("Successfully bound socket");
234233

235-
struct {
234+
struct __attribute__((__packed__)) {
236235
struct nlmsghdr nlh;
237236
struct rtmsg rtm;
238237
struct rtattr rta;
@@ -284,30 +283,20 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
284283
struct sockaddr_nl src_addr = {};
285284
socklen_t src_addr_len = sizeof(src_addr);
286285

287-
struct iovec iov = {};
288-
struct msghdr msg = {
289-
.msg_name = &src_addr,
290-
.msg_namelen = sizeof(src_addr),
291-
.msg_iov = &iov,
292-
.msg_iovlen = 1,
293-
};
286+
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
294287

295-
ssize_t peek_size = recvmsg(sock_fd, &msg, MSG_PEEK | MSG_TRUNC);
296-
if (peek_size < 0) {
297-
FF_DEBUG("Failed to peek message size: errno=%d", errno);
288+
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
289+
(struct sockaddr*)&src_addr, &src_addr_len);
290+
291+
if (received < 0) {
292+
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
298293
return false;
299294
}
300-
FF_DEBUG("Message size: %zd bytes", peek_size);
301-
302-
FF_AUTO_FREE uint8_t* buffer = malloc((size_t)peek_size);
303295

304-
ssize_t received = recvfrom(sock_fd, buffer, (size_t)peek_size, 0,
305-
(struct sockaddr*)&src_addr, &src_addr_len);
306-
if (received != peek_size) {
307-
FF_DEBUG("Failed to receive complete message: received=%zd, expected=%zd", received, peek_size);
296+
if (received >= (ssize_t)sizeof(buffer)) {
297+
FF_DEBUG("Failed to receive complete message (possible truncation)");
308298
return false;
309299
}
310-
FF_DEBUG("Received netlink response: %zd bytes", received);
311300

312301
struct {
313302
uint32_t metric;
@@ -327,6 +316,12 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
327316
break;
328317
}
329318

319+
if (nlh->nlmsg_type == NLMSG_ERROR) {
320+
struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlh);
321+
FF_DEBUG("Netlink reports error: %s", strerror(-err->error));
322+
continue;
323+
}
324+
330325
if (nlh->nlmsg_type != RTM_NEWROUTE)
331326
continue;
332327

@@ -339,7 +334,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
339334
continue;
340335

341336
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
342-
entry = (__typeof__(entry)) { .metric = UINT32_MAX };
337+
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
343338

344339
// Parse route attributes
345340
size_t rtm_len = RTM_PAYLOAD(nlh);
@@ -351,9 +346,8 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
351346
case RTA_DST:
352347
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
353348
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
354-
FF_DEBUG("Found destination: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
355-
struct in6_addr* dst = (struct in6_addr*) RTA_DATA(rta);
356-
if (!IN6_IS_ADDR_UNSPECIFIED(dst)) goto next;
349+
FF_DEBUG("Unexpected RTA_DST: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
350+
goto next;
357351
}
358352
break;
359353
case RTA_OIF:
@@ -373,22 +367,29 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
373367
case RTA_PRIORITY:
374368
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
375369
uint32_t metric = *(uint32_t*) RTA_DATA(rta);
370+
FF_DEBUG("Found metric: %u", metric);
376371
if (metric >= minMetric) goto next;
377372
entry.metric = metric;
378-
FF_DEBUG("Found metric: %u", entry.metric);
379373
}
380374
break;
381375
}
382376
}
383377

384-
if (entry.metric >= minMetric)
378+
if (entry.ifindex == 0 || entry.metric >= minMetric)
385379
{
386380
next:
381+
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
387382
continue;
388383
}
389384
minMetric = entry.metric;
390385
result->ifIndex = entry.ifindex;
391386
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
387+
388+
if (minMetric == 0)
389+
{
390+
FF_DEBUG("Found zero metric route, stopping further processing");
391+
break; // Stop processing if we found a zero metric route
392+
}
392393
}
393394

394395
if (minMetric < UINT32_MAX)

0 commit comments

Comments
 (0)