ohmu
·
2026-10-15
1#include "common/netif.h"
2#include "common/io.h"
3#include "common/mallocHelper.h"
4
5#include <arpa/inet.h>
6#include <net/if.h>
7#include <net/route.h>
8#include <sys/socket.h>
9#include <sys/sockio.h>
10#include <stdio.h>
11
12// loosely based on Haiku's src/bin/network/route/route.cpp
13
14bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
15 FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
16 if (pfRoute < 0) {
17 return false;
18 }
19
20 struct ifconf config;
21 config.ifc_len = sizeof(config.ifc_value);
22 if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) {
23 return false;
24 }
25
26 int size = config.ifc_value;
27 if (size <= 0) {
28 return false;
29 }
30
31 FF_AUTO_FREE void* buffer = malloc((size_t) size);
32 if (buffer == nullptr) {
33 return false;
34 }
35
36 config.ifc_len = size;
37 config.ifc_buf = buffer;
38 if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) {
39 return false;
40 }
41
42 struct ifreq* interface = (struct ifreq*) buffer;
43 struct ifreq* end = (struct ifreq*) ((uint8_t*) buffer + size);
44
45 while (interface < end) {
46 if (interface->ifr_route.flags & RTF_DEFAULT) {
47 // interface->ifr_metric?
48 strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
49 result->ifIndex = if_nametoindex(interface->ifr_name);
50 if (interface->ifr_route.source) {
51 result->preferredSourceAddrV4 = ((struct sockaddr_in*) interface->ifr_route.source)->sin_addr.s_addr;
52 }
53 return true;
54 }
55
56 size_t addressSize = 0;
57 if (interface->ifr_route.destination != nullptr) {
58 addressSize += interface->ifr_route.destination->sa_len;
59 }
60 if (interface->ifr_route.mask != nullptr) {
61 addressSize += interface->ifr_route.mask->sa_len;
62 }
63 if (interface->ifr_route.gateway != nullptr) {
64 addressSize += interface->ifr_route.gateway->sa_len;
65 }
66
67 interface = (struct ifreq*) ((addr_t) interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
68 }
69
70 return false;
71}
72
73bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
74 FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET6, SOCK_RAW, AF_INET6);
75 if (pfRoute < 0) {
76 return false;
77 }
78
79 struct ifconf config;
80 config.ifc_len = sizeof(config.ifc_value);
81 if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) {
82 return false;
83 }
84
85 int size = config.ifc_value;
86 if (size <= 0) {
87 return false;
88 }
89
90 FF_AUTO_FREE void* buffer = malloc((size_t) size);
91 if (buffer == nullptr) {
92 return false;
93 }
94
95 config.ifc_len = size;
96 config.ifc_buf = buffer;
97 if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) {
98 return false;
99 }
100
101 struct ifreq* interface = (struct ifreq*) buffer;
102 struct ifreq* end = (struct ifreq*) ((uint8_t*) buffer + size);
103
104 while (interface < end) {
105 if (interface->ifr_route.flags & RTF_DEFAULT) {
106 strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
107 result->ifIndex = if_nametoindex(interface->ifr_name);
108 return true;
109 }
110
111 size_t addressSize = 0;
112 if (interface->ifr_route.destination != nullptr) {
113 addressSize += interface->ifr_route.destination->sa_len;
114 }
115 if (interface->ifr_route.mask != nullptr) {
116 addressSize += interface->ifr_route.mask->sa_len;
117 }
118 if (interface->ifr_route.gateway != nullptr) {
119 addressSize += interface->ifr_route.gateway->sa_len;
120 }
121
122 interface = (struct ifreq*) ((addr_t) interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
123 }
124 return false;
125}