1
1
#include "netif.h"
2
2
#include "common/io/io.h"
3
+ #include "util/mallocHelper.h"
3
4
5
+ #include <arpa/inet.h>
6
+ #include <linux/rtnetlink.h>
4
7
#include <net/if.h>
5
- #include <stdio.h>
6
8
7
9
#define FF_STR_INDIR (x ) #x
8
10
#define FF_STR (x ) FF_STR_INDIR(x)
9
11
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 )
11
29
{
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;
14
33
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 ;
17
40
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
+ }
23
174
return true;
24
175
}
176
+
25
177
iface [0 ] = '\0' ;
26
178
return false;
27
179
}
@@ -43,9 +195,9 @@ static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
43
195
return false;
44
196
}
45
197
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 )
47
199
{
48
- if (getDefaultRouteIPv4 (iface , ifIndex ))
200
+ if (getDefaultRouteIPv4 (iface , ifIndex , preferredSourceAddr ))
49
201
return true;
50
202
51
203
return getDefaultRouteIPv6 (iface , ifIndex );
0 commit comments