11#include "netif.h"
22#include "common/io/io.h"
3+ #include "util/mallocHelper.h"
34
5+ #include <arpa/inet.h>
6+ #include <linux/rtnetlink.h>
47#include <net/if.h>
5- #include <stdio.h>
68
79#define FF_STR_INDIR (x ) #x
810#define FF_STR (x ) FF_STR_INDIR(x)
911
10- static bool getDefaultRouteIPv4 (char iface [IF_NAMESIZE + 1 ], uint32_t * ifIndex )
12+ struct req_t {
13+ struct nlmsghdr nlh ;
14+ struct rtmsg rtm ;
15+ struct rtattr rta ;
16+ uint32_t table ;
17+ };
18+
19+ struct Route4Entry {
20+ uint32_t dest ;
21+ uint32_t gateway ;
22+ uint32_t src ;
23+ uint8_t prefix_length ;
24+ uint32_t metric ;
25+ uint32_t ifindex ;
26+ };
27+
28+ static bool getDefaultRouteIPv4 (char iface [IF_NAMESIZE + 1 ], uint32_t * ifIndex , uint32_t * preferredSourceAddr )
1129{
12- FILE * FF_AUTO_CLOSE_FILE netRoute = fopen ("/proc/net/route" , "r" );
13- if (!netRoute ) return false;
30+ FF_AUTO_CLOSE_FD int sock_fd = socket (AF_NETLINK , SOCK_RAW | SOCK_CLOEXEC , NETLINK_ROUTE );
31+ if (sock_fd < 0 )
32+ return false;
1433
15- // skip first line
16- FF_UNUSED (fscanf (netRoute , "%*[^\n]\n" ));
34+ // Bind socket
35+ struct sockaddr_nl addr ;
36+ memset (& addr , 0 , sizeof (addr ));
37+ addr .nl_family = AF_NETLINK ;
38+ addr .nl_pid = 0 ; // Let kernel assign PID
39+ addr .nl_groups = 0 ;
1740
18- unsigned long long destination ; //, gateway, flags, refCount, use, metric, mask, mtu, ...
19- while (fscanf (netRoute , "%" FF_STR (IF_NAMESIZE ) "s%llx%*[^\n]" , iface , & destination ) == 2 )
20- {
21- if (destination != 0 ) continue ;
22- * ifIndex = if_nametoindex (iface );
41+ if (bind (sock_fd , (struct sockaddr * )& addr , sizeof (addr )) < 0 ) {
42+ return false;
43+ }
44+
45+ struct req_t req ;
46+ memset (& req , 0 , sizeof (req ));
47+
48+ // Netlink message header
49+ req .nlh .nlmsg_len = sizeof (req );
50+ req .nlh .nlmsg_type = RTM_GETROUTE ;
51+ req .nlh .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP ;
52+ req .nlh .nlmsg_seq = 0 ;
53+ req .nlh .nlmsg_pid = 0 ;
54+
55+ // Route message
56+ req .rtm .rtm_family = AF_INET ;
57+ req .rtm .rtm_dst_len = 0 ;
58+ req .rtm .rtm_src_len = 0 ;
59+ req .rtm .rtm_tos = 0 ;
60+ req .rtm .rtm_table = RT_TABLE_UNSPEC ;
61+ req .rtm .rtm_protocol = RTPROT_UNSPEC ;
62+ req .rtm .rtm_scope = RT_SCOPE_UNIVERSE ;
63+ req .rtm .rtm_type = RTN_UNSPEC ;
64+ req .rtm .rtm_flags = 0 ;
65+
66+ // Route attribute for main table
67+ req .rta .rta_len = RTA_LENGTH (sizeof (uint32_t ));
68+ req .rta .rta_type = RTA_TABLE ;
69+ req .table = RT_TABLE_MAIN ;
70+
71+ struct sockaddr_nl dest_addr ;
72+ memset (& dest_addr , 0 , sizeof (dest_addr ));
73+ dest_addr .nl_family = AF_NETLINK ;
74+ dest_addr .nl_pid = 0 ;
75+ dest_addr .nl_groups = 0 ;
76+
77+ ssize_t sent = sendto (sock_fd , & req , sizeof (req ), 0 ,
78+ (struct sockaddr * )& dest_addr , sizeof (dest_addr ));
79+
80+ if (sent != sizeof (req )) {
81+ return false;
82+ }
83+
84+ struct sockaddr_nl src_addr ;
85+ socklen_t src_addr_len = sizeof (src_addr );
86+ struct iovec iov = {NULL , 0 };
87+ struct msghdr msg ;
88+
89+ memset (& msg , 0 , sizeof (msg ));
90+ msg .msg_name = & src_addr ;
91+ msg .msg_namelen = sizeof (src_addr );
92+ msg .msg_iov = & iov ;
93+ msg .msg_iovlen = 1 ;
94+
95+ ssize_t peek_size = recvmsg (sock_fd , & msg , MSG_PEEK | MSG_TRUNC );
96+ if (peek_size < 0 ) {
97+ return false;
98+ }
99+
100+ FF_AUTO_FREE uint8_t * buffer = malloc ((size_t )peek_size );
101+
102+ ssize_t received = recvfrom (sock_fd , buffer , (size_t )peek_size , 0 ,
103+ (struct sockaddr * )& src_addr , & src_addr_len );
104+ if (received != peek_size ) {
105+ return false;
106+ }
107+
108+ struct Route4Entry best_gw ;
109+ memset (& best_gw , 0 , sizeof (best_gw ));
110+
111+ for (const struct nlmsghdr * nlh = (struct nlmsghdr * )buffer ;
112+ NLMSG_OK (nlh , received );
113+ nlh = NLMSG_NEXT (nlh , received )) {
114+
115+ if (nlh -> nlmsg_type == NLMSG_DONE )
116+ break ;
117+
118+ if (nlh -> nlmsg_type != RTM_NEWROUTE )
119+ continue ;
120+
121+ struct rtmsg * rtm = (struct rtmsg * )NLMSG_DATA (nlh );
122+ if (rtm -> rtm_family != AF_INET )
123+ continue ;
124+
125+ struct Route4Entry entry ;
126+ memset (& entry , 0 , sizeof (struct Route4Entry ));
127+ entry .prefix_length = rtm -> rtm_dst_len ;
128+
129+ // Parse route attributes
130+ size_t rtm_len = RTM_PAYLOAD (nlh );
131+ for (struct rtattr * rta = RTM_RTA (rtm );
132+ RTA_OK (rta , rtm_len );
133+ rta = RTA_NEXT (rta , rtm_len )) {
134+
135+ switch (rta -> rta_type ) {
136+ case RTA_DST :
137+ entry .dest = * (uint32_t * )RTA_DATA (rta );
138+ break ;
139+ case RTA_GATEWAY :
140+ entry .gateway = * (uint32_t * )RTA_DATA (rta );
141+ break ;
142+ case RTA_PREFSRC :
143+ entry .src = * (uint32_t * )RTA_DATA (rta );
144+ break ;
145+ case RTA_PRIORITY :
146+ entry .metric = * (uint32_t * )RTA_DATA (rta );
147+ break ;
148+ case RTA_OIF :
149+ entry .ifindex = * (uint32_t * )RTA_DATA (rta );
150+ break ;
151+ }
152+ }
153+
154+ if (entry .gateway == 0 || entry .dest != 0 || entry .prefix_length != 0 )
155+ continue ;
156+
157+ if (best_gw .gateway == 0 || entry .metric < best_gw .metric ) {
158+ memcpy (& best_gw , & entry , sizeof (struct Route4Entry ));
159+ }
160+ }
161+
162+ if (best_gw .gateway != 0 ) {
163+ if (ifIndex ) {
164+ * ifIndex = best_gw .ifindex ;
165+ }
166+ if (iface ) {
167+ if (if_indextoname (best_gw .ifindex , iface ) == NULL ) {
168+ iface [0 ] = '\0' ;
169+ }
170+ }
171+ if (preferredSourceAddr ) {
172+ * preferredSourceAddr = best_gw .src ;
173+ }
23174 return true;
24175 }
176+
25177 iface [0 ] = '\0' ;
26178 return false;
27179}
@@ -43,9 +195,9 @@ static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
43195 return false;
44196}
45197
46- bool ffNetifGetDefaultRouteImpl (char iface [IF_NAMESIZE + 1 ], uint32_t * ifIndex )
198+ bool ffNetifGetDefaultRouteImpl (char iface [IF_NAMESIZE + 1 ], uint32_t * ifIndex , uint32_t * preferredSourceAddr )
47199{
48- if (getDefaultRouteIPv4 (iface , ifIndex ))
200+ if (getDefaultRouteIPv4 (iface , ifIndex , preferredSourceAddr ))
49201 return true;
50202
51203 return getDefaultRouteIPv6 (iface , ifIndex );
0 commit comments