1 /* $Id: getgateway.c,v 1.22 2011/08/08 21:20:51 nanard Exp $ */
4 Copyright (c) 2007-2011, Thomas BERNARD
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.
33 #include <netinet/in.h>
35 #if !defined(_MSC_VER)
36 #include <sys/param.h>
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
44 * In MS Windows, default gateway is found by looking into the registry
45 * or by using GetBestRoute(). */
47 #define USE_PROC_NET_ROUTE
48 #undef USE_SOCKET_ROUTE
49 #undef USE_SYSCTL_NET_ROUTE
52 #if defined(BSD) || defined(__FreeBSD_kernel__)
53 #undef USE_PROC_NET_ROUTE
54 #define USE_SOCKET_ROUTE
55 #undef USE_SYSCTL_NET_ROUTE
59 #undef USE_PROC_NET_ROUTE
60 #undef USE_SOCKET_ROUTE
61 #define USE_SYSCTL_NET_ROUTE
64 #if (defined(sun) && defined(__SVR4))
65 #undef USE_PROC_NET_ROUTE
66 #define USE_SOCKET_ROUTE
67 #undef USE_SYSCTL_NET_ROUTE
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
79 #undef USE_PROC_NET_ROUTE
80 #undef USE_SOCKET_ROUTE
81 #undef USE_SYSCTL_NET_ROUTE
82 #define USE_WIN32_CODE
84 #include <w32api/windef.h>
85 #include <w32api/winbase.h>
86 #include <w32api/winreg.h>
93 #include <sys/sockio.h>
94 #define USE_HAIKU_CODE
97 #ifdef USE_SYSCTL_NET_ROUTE
99 #include <sys/sysctl.h>
100 #include <sys/socket.h>
101 #include <net/route.h>
103 #ifdef USE_SOCKET_ROUTE
106 #include <sys/socket.h>
108 #include <net/route.h>
111 #ifdef USE_WIN32_CODE
114 #define MAX_KEY_LENGTH 255
115 #define MAX_VALUE_LENGTH 16383
118 #ifdef USE_WIN32_CODE_2
120 #include <iphlpapi.h>
123 #include "getgateway.h"
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
)
149 f
= fopen("/proc/net/route", "r");
152 while(fgets(buf
, sizeof(buf
), f
)) {
153 if(line
> 0) { /* skip the first line */
155 /* skip the interface name */
156 while(*p
&& !isspace(*p
))
158 while(*p
&& isspace(*p
))
160 if(sscanf(p
, "%lx%lx", &d
, &g
)==2) {
161 if(d
== 0 && g
!= 0) { /* default */
170 /* default route not found ! */
175 #endif /* #ifdef USE_PROC_NET_ROUTE */
178 #ifdef USE_SYSCTL_NET_ROUTE
181 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
183 int getdefaultgateway(in_addr_t
* addr
)
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*/};
190 /* net.route.0.inet.flags.gateway */
191 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
,
192 NET_RT_FLAGS
, RTF_GATEWAY
};
195 struct rt_msghdr
* rt
;
196 struct sockaddr
* sa
;
197 struct sockaddr
* sa_tab
[RTAX_MAX
];
200 if(sysctl(mib
, sizeof(mib
)/sizeof(int), 0, &l
, 0, 0) < 0) {
205 if(sysctl(mib
, sizeof(mib
)/sizeof(int), buf
, &l
, 0, 0) < 0) {
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
)) {
215 sa
= (struct sockaddr
*)((char *)sa
+ ROUNDUP(sa
->sa_len
));
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
;
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
246 struct rt_msghdr m_rtm
;
250 int getdefaultgateway(in_addr_t
*addr
)
252 int s
, seq
, l
, rtm_addrs
, i
;
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
;
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
;
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) {
289 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
290 } while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
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
)
304 cp
+= sizeof(struct sockaddr
);
312 *addr
= ((struct sockaddr_in
*)gate
)->sin_addr
.s_addr
;
318 #endif /* #ifdef USE_SOCKET_ROUTE */
320 #ifdef USE_WIN32_CODE
321 LIBSPEC
int getdefaultgateway(in_addr_t
* addr
)
323 HKEY networkCardsKey
;
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
;
339 //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
340 //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
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"
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"
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:
360 // -Description = Broadcom 802.11n Network Adapter
361 // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
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:
371 // -{3a539854-6a70-11db-887c-806e6f6e6963}
372 // -DhcpIPAddress = 0.0.0.0
374 // -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
375 // -DhcpIPAddress = 10.0.1.4
376 // -DhcpDefaultGateway = 10.0.1.1
378 // -{86226414-5545-4335-A9D1-5BD7120119AD}
379 // -DhcpIpAddress = 10.0.1.5
380 // -DhcpDefaultGateay = 10.0.1.1
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
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
);
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);
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);
471 RegCloseKey(interfaceKey
);
474 RegCloseKey(networkCardKey
);
479 RegCloseKey(interfacesKey
);
480 RegCloseKey(networkCardsKey
);
486 for(i
= 0; i
< 32; i
++) {
487 tmp
[i
] = (char)gatewayValue
[i
];
492 *addr
= inet_addr(tmp
);
494 *addr
= inet_addr(gatewayValue
);
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
)
510 *addr
= ip_forward
.dwForwardNextHop
;
513 #endif /* #ifdef USE_WIN32_CODE_2 */
515 #ifdef USE_HAIKU_CODE
516 int getdefaultgateway(in_addr_t
*addr
)
519 struct ifconf config
;
521 struct ifreq
*interface
;
523 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
526 if (ioctl(fd
, SIOCGRTSIZE
, &config
, sizeof(config
)) != 0) {
529 if (config
.ifc_value
< 1) {
530 goto fail
; /* No routes */
532 if ((buffer
= malloc(config
.ifc_value
)) == NULL
) {
535 config
.ifc_len
= config
.ifc_value
;
536 config
.ifc_buf
= buffer
;
537 if (ioctl(fd
, SIOCGRTTABLE
, &config
, sizeof(config
)) != 0) {
540 for (interface
= buffer
;
541 (uint8_t *)interface
< (uint8_t *)buffer
+ config
.ifc_len
; ) {
542 struct route_entry route
= interface
->ifr_route
;
544 if (route
.flags
& (RTF_GATEWAY
| RTF_DEFAULT
)) {
545 *addr
= ((struct sockaddr_in
*)route
.gateway
)->sin_addr
.s_addr
;
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
);
566 #endif /* #ifdef USE_HAIKU_CODE */