transmission 2.51 update
[tomato.git] / release / src / router / transmission / third-party / libnatpmp / getgateway.c
blobcb84dee88b12e0e58f284da7d194d1c6700dc2a9
1 /* $Id: getgateway.c,v 1.22 2011/08/08 21:20:51 nanard Exp $ */
2 /* libnatpmp
4 Copyright (c) 2007-2011, Thomas BERNARD
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 * The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 POSSIBILITY OF SUCH DAMAGE.
30 #include <stdio.h>
31 #include <ctype.h>
32 #ifndef WIN32
33 #include <netinet/in.h>
34 #endif
35 #if !defined(_MSC_VER)
36 #include <sys/param.h>
37 #endif
38 /* There is no portable method to get the default route gateway.
39 * So below are four (or five ?) differents functions implementing this.
40 * Parsing /proc/net/route is for linux.
41 * sysctl is the way to access such informations on BSD systems.
42 * Many systems should provide route information through raw PF_ROUTE
43 * sockets.
44 * In MS Windows, default gateway is found by looking into the registry
45 * or by using GetBestRoute(). */
46 #ifdef __linux__
47 #define USE_PROC_NET_ROUTE
48 #undef USE_SOCKET_ROUTE
49 #undef USE_SYSCTL_NET_ROUTE
50 #endif
52 #if defined(BSD) || defined(__FreeBSD_kernel__)
53 #undef USE_PROC_NET_ROUTE
54 #define USE_SOCKET_ROUTE
55 #undef USE_SYSCTL_NET_ROUTE
56 #endif
58 #ifdef __APPLE__
59 #undef USE_PROC_NET_ROUTE
60 #undef USE_SOCKET_ROUTE
61 #define USE_SYSCTL_NET_ROUTE
62 #endif
64 #if (defined(sun) && defined(__SVR4))
65 #undef USE_PROC_NET_ROUTE
66 #define USE_SOCKET_ROUTE
67 #undef USE_SYSCTL_NET_ROUTE
68 #endif
70 #ifdef WIN32
71 #undef USE_PROC_NET_ROUTE
72 #undef USE_SOCKET_ROUTE
73 #undef USE_SYSCTL_NET_ROUTE
74 //#define USE_WIN32_CODE
75 #define USE_WIN32_CODE_2
76 #endif
78 #ifdef __CYGWIN__
79 #undef USE_PROC_NET_ROUTE
80 #undef USE_SOCKET_ROUTE
81 #undef USE_SYSCTL_NET_ROUTE
82 #define USE_WIN32_CODE
83 #include <stdarg.h>
84 #include <w32api/windef.h>
85 #include <w32api/winbase.h>
86 #include <w32api/winreg.h>
87 #endif
89 #ifdef __HAIKU__
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <net/if.h>
93 #include <sys/sockio.h>
94 #define USE_HAIKU_CODE
95 #endif
97 #ifdef USE_SYSCTL_NET_ROUTE
98 #include <stdlib.h>
99 #include <sys/sysctl.h>
100 #include <sys/socket.h>
101 #include <net/route.h>
102 #endif
103 #ifdef USE_SOCKET_ROUTE
104 #include <unistd.h>
105 #include <string.h>
106 #include <sys/socket.h>
107 #include <net/if.h>
108 #include <net/route.h>
109 #endif
111 #ifdef USE_WIN32_CODE
112 #include <unknwn.h>
113 #include <winreg.h>
114 #define MAX_KEY_LENGTH 255
115 #define MAX_VALUE_LENGTH 16383
116 #endif
118 #ifdef USE_WIN32_CODE_2
119 #include <windows.h>
120 #include <iphlpapi.h>
121 #endif
123 #include "getgateway.h"
125 #ifndef WIN32
126 #define SUCCESS (0)
127 #define FAILED (-1)
128 #endif
130 #ifdef USE_PROC_NET_ROUTE
132 parse /proc/net/route which is as follow :
134 Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
135 wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0
136 eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0
137 wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0
138 eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0
140 One header line, and then one line by route by route table entry.
142 int getdefaultgateway(in_addr_t * addr)
144 unsigned long d, g;
145 char buf[256];
146 int line = 0;
147 FILE * f;
148 char * p;
149 f = fopen("/proc/net/route", "r");
150 if(!f)
151 return FAILED;
152 while(fgets(buf, sizeof(buf), f)) {
153 if(line > 0) { /* skip the first line */
154 p = buf;
155 /* skip the interface name */
156 while(*p && !isspace(*p))
157 p++;
158 while(*p && isspace(*p))
159 p++;
160 if(sscanf(p, "%lx%lx", &d, &g)==2) {
161 if(d == 0 && g != 0) { /* default */
162 *addr = g;
163 fclose(f);
164 return SUCCESS;
168 line++;
170 /* default route not found ! */
171 if(f)
172 fclose(f);
173 return FAILED;
175 #endif /* #ifdef USE_PROC_NET_ROUTE */
178 #ifdef USE_SYSCTL_NET_ROUTE
180 #define ROUNDUP(a) \
181 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
183 int getdefaultgateway(in_addr_t * addr)
185 #if 0
186 /* net.route.0.inet.dump.0.0 ? */
187 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
188 NET_RT_DUMP, 0, 0/*tableid*/};
189 #endif
190 /* net.route.0.inet.flags.gateway */
191 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
192 NET_RT_FLAGS, RTF_GATEWAY};
193 size_t l;
194 char * buf, * p;
195 struct rt_msghdr * rt;
196 struct sockaddr * sa;
197 struct sockaddr * sa_tab[RTAX_MAX];
198 int i;
199 int r = FAILED;
200 if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
201 return FAILED;
203 if(l>0) {
204 buf = malloc(l);
205 if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
206 free(buf);
207 return FAILED;
209 for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
210 rt = (struct rt_msghdr *)p;
211 sa = (struct sockaddr *)(rt + 1);
212 for(i=0; i<RTAX_MAX; i++) {
213 if(rt->rtm_addrs & (1 << i)) {
214 sa_tab[i] = sa;
215 sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
216 } else {
217 sa_tab[i] = NULL;
220 if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
221 && sa_tab[RTAX_DST]->sa_family == AF_INET
222 && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
223 if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
224 *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
225 r = SUCCESS;
229 free(buf);
231 return r;
233 #endif /* #ifdef USE_SYSCTL_NET_ROUTE */
236 #ifdef USE_SOCKET_ROUTE
237 /* Thanks to Darren Kenny for this code */
238 #define NEXTADDR(w, u) \
239 if (rtm_addrs & (w)) {\
240 l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
243 #define rtm m_rtmsg.m_rtm
245 struct {
246 struct rt_msghdr m_rtm;
247 char m_space[512];
248 } m_rtmsg;
250 int getdefaultgateway(in_addr_t *addr)
252 int s, seq, l, rtm_addrs, i;
253 pid_t pid;
254 struct sockaddr so_dst, so_mask;
255 char *cp = m_rtmsg.m_space;
256 struct sockaddr *gate = NULL, *sa;
257 struct rt_msghdr *msg_hdr;
259 pid = getpid();
260 seq = 0;
261 rtm_addrs = RTA_DST | RTA_NETMASK;
263 memset(&so_dst, 0, sizeof(so_dst));
264 memset(&so_mask, 0, sizeof(so_mask));
265 memset(&rtm, 0, sizeof(struct rt_msghdr));
267 rtm.rtm_type = RTM_GET;
268 rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
269 rtm.rtm_version = RTM_VERSION;
270 rtm.rtm_seq = ++seq;
271 rtm.rtm_addrs = rtm_addrs;
273 so_dst.sa_family = AF_INET;
274 so_mask.sa_family = AF_INET;
276 NEXTADDR(RTA_DST, so_dst);
277 NEXTADDR(RTA_NETMASK, so_mask);
279 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
281 s = socket(PF_ROUTE, SOCK_RAW, 0);
283 if (write(s, (char *)&m_rtmsg, l) < 0) {
284 close(s);
285 return FAILED;
288 do {
289 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
290 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
292 close(s);
294 msg_hdr = &rtm;
296 cp = ((char *)(msg_hdr + 1));
297 if (msg_hdr->rtm_addrs) {
298 for (i = 1; i; i <<= 1)
299 if (i & msg_hdr->rtm_addrs) {
300 sa = (struct sockaddr *)cp;
301 if (i == RTA_GATEWAY )
302 gate = sa;
304 cp += sizeof(struct sockaddr);
306 } else {
307 return FAILED;
311 if (gate != NULL ) {
312 *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr;
313 return SUCCESS;
314 } else {
315 return FAILED;
318 #endif /* #ifdef USE_SOCKET_ROUTE */
320 #ifdef USE_WIN32_CODE
321 LIBSPEC int getdefaultgateway(in_addr_t * addr)
323 HKEY networkCardsKey;
324 HKEY networkCardKey;
325 HKEY interfacesKey;
326 HKEY interfaceKey;
327 DWORD i = 0;
328 DWORD numSubKeys = 0;
329 TCHAR keyName[MAX_KEY_LENGTH];
330 DWORD keyNameLength = MAX_KEY_LENGTH;
331 TCHAR keyValue[MAX_VALUE_LENGTH];
332 DWORD keyValueLength = MAX_VALUE_LENGTH;
333 DWORD keyValueType = REG_SZ;
334 TCHAR gatewayValue[MAX_VALUE_LENGTH];
335 DWORD gatewayValueLength = MAX_VALUE_LENGTH;
336 DWORD gatewayValueType = REG_MULTI_SZ;
337 int done = 0;
339 //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
340 //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
341 #ifdef UNICODE
342 LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
343 LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
344 #define STR_SERVICENAME L"ServiceName"
345 #define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway"
346 #define STR_DEFAULTGATEWAY L"DefaultGateway"
347 #else
348 LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
349 LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
350 #define STR_SERVICENAME "ServiceName"
351 #define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway"
352 #define STR_DEFAULTGATEWAY "DefaultGateway"
353 #endif
354 // The windows registry lists its primary network devices in the following location:
355 // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
357 // Each network device has its own subfolder, named with an index, with various properties:
358 // -NetworkCards
359 // -5
360 // -Description = Broadcom 802.11n Network Adapter
361 // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
362 // -8
363 // -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
364 // -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
366 // The above service name is the name of a subfolder within:
367 // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
369 // There may be more subfolders in this interfaces path than listed in the network cards path above:
370 // -Interfaces
371 // -{3a539854-6a70-11db-887c-806e6f6e6963}
372 // -DhcpIPAddress = 0.0.0.0
373 // -[more]
374 // -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
375 // -DhcpIPAddress = 10.0.1.4
376 // -DhcpDefaultGateway = 10.0.1.1
377 // -[more]
378 // -{86226414-5545-4335-A9D1-5BD7120119AD}
379 // -DhcpIpAddress = 10.0.1.5
380 // -DhcpDefaultGateay = 10.0.1.1
381 // -[more]
383 // In order to extract this information, we enumerate each network card, and extract the ServiceName value.
384 // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value.
385 // Once one is found, we're done.
387 // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value.
388 // However, the technique used is the technique most cited on the web, and we assume it to be more correct.
390 if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key
391 networkCardsPath, // Name of registry subkey to open
392 0, // Reserved - must be zero
393 KEY_READ, // Mask - desired access rights
394 &networkCardsKey)) // Pointer to output key
396 // Unable to open network cards keys
397 return -1;
400 if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key
401 interfacesPath, // Name of registry subkey to open
402 0, // Reserved - must be zero
403 KEY_READ, // Mask - desired access rights
404 &interfacesKey)) // Pointer to output key
406 // Unable to open interfaces key
407 RegCloseKey(networkCardsKey);
408 return -1;
411 // Figure out how many subfolders are within the NetworkCards folder
412 RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
414 //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
416 // Enumrate through each subfolder within the NetworkCards folder
417 for(i = 0; i < numSubKeys && !done; i++)
419 keyNameLength = MAX_KEY_LENGTH;
420 if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key
421 i, // Index of subkey to retrieve
422 keyName, // Buffer that receives the name of the subkey
423 &keyNameLength, // Variable that receives the size of the above buffer
424 NULL, // Reserved - must be NULL
425 NULL, // Buffer that receives the class string
426 NULL, // Variable that receives the size of the above buffer
427 NULL)) // Variable that receives the last write time of subkey
429 if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS)
431 keyValueLength = MAX_VALUE_LENGTH;
432 if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key
433 STR_SERVICENAME, // Name of key to query
434 NULL, // Reserved - must be NULL
435 &keyValueType, // Receives value type
436 (LPBYTE)keyValue, // Receives value
437 &keyValueLength)) // Receives value length in bytes
439 // printf("keyValue: %s\n", keyValue);
440 if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS)
442 gatewayValueLength = MAX_VALUE_LENGTH;
443 if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
444 STR_DHCPDEFAULTGATEWAY, // Name of key to query
445 NULL, // Reserved - must be NULL
446 &gatewayValueType, // Receives value type
447 (LPBYTE)gatewayValue, // Receives value
448 &gatewayValueLength)) // Receives value length in bytes
450 // Check to make sure it's a string
451 if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
453 //printf("gatewayValue: %s\n", gatewayValue);
454 done = 1;
457 else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
458 STR_DEFAULTGATEWAY, // Name of key to query
459 NULL, // Reserved - must be NULL
460 &gatewayValueType, // Receives value type
461 (LPBYTE)gatewayValue,// Receives value
462 &gatewayValueLength)) // Receives value length in bytes
464 // Check to make sure it's a string
465 if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
467 //printf("gatewayValue: %s\n", gatewayValue);
468 done = 1;
471 RegCloseKey(interfaceKey);
474 RegCloseKey(networkCardKey);
479 RegCloseKey(interfacesKey);
480 RegCloseKey(networkCardsKey);
482 if(done)
484 #if UNICODE
485 char tmp[32];
486 for(i = 0; i < 32; i++) {
487 tmp[i] = (char)gatewayValue[i];
488 if(!tmp[i])
489 break;
491 tmp[31] = '\0';
492 *addr = inet_addr(tmp);
493 #else
494 *addr = inet_addr(gatewayValue);
495 #endif
496 return 0;
499 return -1;
501 #endif /* #ifdef USE_WIN32_CODE */
503 #ifdef USE_WIN32_CODE_2
504 int getdefaultgateway(in_addr_t *addr)
506 MIB_IPFORWARDROW ip_forward;
507 memset(&ip_forward, 0, sizeof(ip_forward));
508 if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR)
509 return -1;
510 *addr = ip_forward.dwForwardNextHop;
511 return 0;
513 #endif /* #ifdef USE_WIN32_CODE_2 */
515 #ifdef USE_HAIKU_CODE
516 int getdefaultgateway(in_addr_t *addr)
518 int fd, ret = -1;
519 struct ifconf config;
520 void *buffer = NULL;
521 struct ifreq *interface;
523 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
524 return -1;
526 if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) {
527 goto fail;
529 if (config.ifc_value < 1) {
530 goto fail; /* No routes */
532 if ((buffer = malloc(config.ifc_value)) == NULL) {
533 goto fail;
535 config.ifc_len = config.ifc_value;
536 config.ifc_buf = buffer;
537 if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) {
538 goto fail;
540 for (interface = buffer;
541 (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) {
542 struct route_entry route = interface->ifr_route;
543 int intfSize;
544 if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) {
545 *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr;
546 ret = 0;
547 break;
549 intfSize = sizeof(route) + IF_NAMESIZE;
550 if (route.destination != NULL) {
551 intfSize += route.destination->sa_len;
553 if (route.mask != NULL) {
554 intfSize += route.mask->sa_len;
556 if (route.gateway != NULL) {
557 intfSize += route.gateway->sa_len;
559 interface = (struct ifreq *)((uint8_t *)interface + intfSize);
561 fail:
562 free(buffer);
563 close(fd);
564 return ret;
566 #endif /* #ifdef USE_HAIKU_CODE */