source: trunk/third-party/libnatpmp/getgateway.c @ 10284

Last change on this file since 10284 was 10284, checked in by livings124, 12 years ago

update libnatpmp to 20100202

File size: 17.2 KB
Line 
1/* $Id: getgateway.c,v 1.19 2009/12/19 15:20:45 nanard Exp $ */
2/* libnatpmp
3 * Copyright (c) 2007-2009, Thomas BERNARD <miniupnp@free.fr>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
16#include <stdio.h>
17#include <ctype.h>
18#ifndef WIN32
19#include <netinet/in.h>
20#endif
21#if !defined(_MSC_VER)
22#include <sys/param.h>
23#endif
24/* There is no portable method to get the default route gateway.
25 * So below are four (or five ?) differents functions implementing this.
26 * Parsing /proc/net/route is for linux.
27 * sysctl is the way to access such informations on BSD systems.
28 * Many systems should provide route information through raw PF_ROUTE
29 * sockets.
30 * In MS Windows, default gateway is found by looking into the registry
31 * or by using GetBestRoute(). */
32#ifdef __linux__
33#define USE_PROC_NET_ROUTE
34#undef USE_SOCKET_ROUTE
35#undef USE_SYSCTL_NET_ROUTE
36#endif
37
38#ifdef BSD
39#undef USE_PROC_NET_ROUTE
40#define USE_SOCKET_ROUTE
41#undef USE_SYSCTL_NET_ROUTE
42#endif
43
44#ifdef __APPLE__
45#undef USE_PROC_NET_ROUTE
46#undef USE_SOCKET_ROUTE
47#define USE_SYSCTL_NET_ROUTE
48#endif
49
50#if (defined(sun) && defined(__SVR4))
51#undef USE_PROC_NET_ROUTE
52#define USE_SOCKET_ROUTE
53#undef USE_SYSCTL_NET_ROUTE
54#endif
55
56#ifdef WIN32
57#undef USE_PROC_NET_ROUTE
58#undef USE_SOCKET_ROUTE
59#undef USE_SYSCTL_NET_ROUTE
60//#define USE_WIN32_CODE
61#define USE_WIN32_CODE_2
62#endif
63
64#ifdef __CYGWIN__
65#undef USE_PROC_NET_ROUTE
66#undef USE_SOCKET_ROUTE
67#undef USE_SYSCTL_NET_ROUTE
68#define USE_WIN32_CODE
69#include <stdarg.h>
70#include <w32api/windef.h>
71#include <w32api/winbase.h>
72#include <w32api/winreg.h>
73#endif
74
75#ifdef __HAIKU__
76#include <stdlib.h>
77#include <unistd.h>
78#include <net/if.h>
79#include <sys/sockio.h>
80#define USE_HAIKU_CODE
81#endif
82
83#ifdef USE_SYSCTL_NET_ROUTE
84#include <stdlib.h>
85#include <sys/sysctl.h>
86#include <sys/socket.h>
87#include <net/route.h>
88#endif
89#ifdef USE_SOCKET_ROUTE
90#include <unistd.h>
91#include <string.h>
92#include <sys/socket.h>
93#include <net/if.h>
94#include <net/route.h>
95#endif
96
97#ifdef USE_WIN32_CODE
98#include <unknwn.h>
99#include <winreg.h>
100#define MAX_KEY_LENGTH 255
101#define MAX_VALUE_LENGTH 16383
102#endif
103
104#ifdef USE_WIN32_CODE_2
105#include <windows.h>
106#include <iphlpapi.h>
107#endif
108
109#include "getgateway.h"
110
111#ifndef WIN32
112#define SUCCESS (0)
113#define FAILED  (-1)
114#endif
115
116#ifdef USE_PROC_NET_ROUTE
117/*
118 parse /proc/net/route which is as follow :
119
120Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask            MTU     Window  IRTT           
121wlan0   0001A8C0        00000000        0001    0       0       0       00FFFFFF        0       0       0             
122eth0    0000FEA9        00000000        0001    0       0       0       0000FFFF        0       0       0             
123wlan0   00000000        0101A8C0        0003    0       0       0       00000000        0       0       0             
124eth0    00000000        00000000        0001    0       0       1000    00000000        0       0       0             
125
126 One header line, and then one line by route by route table entry.
127*/
128int getdefaultgateway(in_addr_t * addr)
129{
130        unsigned long d, g;
131        char buf[256];
132        int line = 0;
133        FILE * f;
134        char * p;
135        f = fopen("/proc/net/route", "r");
136        if(!f)
137                return FAILED;
138        while(fgets(buf, sizeof(buf), f)) {
139                if(line > 0) {  /* skip the first line */
140                        p = buf;
141                        /* skip the interface name */
142                        while(*p && !isspace(*p))
143                                p++;
144                        while(*p && isspace(*p))
145                                p++;
146                        if(sscanf(p, "%lx%lx", &d, &g)==2) {
147                                if(d == 0 && g != 0) { /* default */
148                                        *addr = g;
149                                        fclose(f);
150                                        return SUCCESS;
151                                }
152                        }
153                }
154                line++;
155        }
156        /* default route not found ! */
157        if(f)
158                fclose(f);
159        return FAILED;
160}
161#endif /* #ifdef USE_PROC_NET_ROUTE */
162
163
164#ifdef USE_SYSCTL_NET_ROUTE
165
166#define ROUNDUP(a) \
167        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
168
169int getdefaultgateway(in_addr_t * addr)
170{
171#if 0
172        /* net.route.0.inet.dump.0.0 ? */
173        int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
174                     NET_RT_DUMP, 0, 0/*tableid*/};
175#endif
176        /* net.route.0.inet.flags.gateway */
177        int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
178                     NET_RT_FLAGS, RTF_GATEWAY};
179        size_t l;
180        char * buf, * p;
181        struct rt_msghdr * rt;
182        struct sockaddr * sa;
183        struct sockaddr * sa_tab[RTAX_MAX];
184        int i;
185        int r = FAILED;
186        if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
187                return FAILED;
188        }
189        if(l>0) {
190                buf = malloc(l);
191                if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
192                        free(buf);
193                        return FAILED;
194                }
195                for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
196                        rt = (struct rt_msghdr *)p;
197                        sa = (struct sockaddr *)(rt + 1);
198                        for(i=0; i<RTAX_MAX; i++) {
199                                if(rt->rtm_addrs & (1 << i)) {
200                                        sa_tab[i] = sa;
201                                        sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
202                                } else {
203                                        sa_tab[i] = NULL;
204                                }
205                        }
206                        if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
207              && sa_tab[RTAX_DST]->sa_family == AF_INET
208              && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
209                                if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
210                                        *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
211                                        r = SUCCESS;
212                                }
213                        }
214                }
215                free(buf);
216        }
217        return r;
218}
219#endif /* #ifdef USE_SYSCTL_NET_ROUTE */
220
221
222#ifdef USE_SOCKET_ROUTE
223/* Thanks to Darren Kenny for this code */
224#define NEXTADDR(w, u) \
225        if (rtm_addrs & (w)) {\
226            l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
227        }
228
229#define rtm m_rtmsg.m_rtm
230
231struct {
232  struct rt_msghdr m_rtm;
233  char       m_space[512];
234} m_rtmsg;
235
236int getdefaultgateway(in_addr_t *addr)
237{
238  int s, seq, l, rtm_addrs, i;
239  pid_t pid;
240  struct sockaddr so_dst, so_mask;
241  char *cp = m_rtmsg.m_space; 
242  struct sockaddr *gate = NULL, *sa;
243  struct rt_msghdr *msg_hdr;
244
245  pid = getpid();
246  seq = 0;
247  rtm_addrs = RTA_DST | RTA_NETMASK;
248
249  memset(&so_dst, 0, sizeof(so_dst));
250  memset(&so_mask, 0, sizeof(so_mask));
251  memset(&rtm, 0, sizeof(struct rt_msghdr));
252
253  rtm.rtm_type = RTM_GET;
254  rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
255  rtm.rtm_version = RTM_VERSION;
256  rtm.rtm_seq = ++seq;
257  rtm.rtm_addrs = rtm_addrs; 
258
259  so_dst.sa_family = AF_INET;
260  so_mask.sa_family = AF_INET;
261
262  NEXTADDR(RTA_DST, so_dst);
263  NEXTADDR(RTA_NETMASK, so_mask);
264
265  rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
266
267  s = socket(PF_ROUTE, SOCK_RAW, 0);
268
269  if (write(s, (char *)&m_rtmsg, l) < 0) {
270      close(s);
271      return FAILED;
272  }
273
274  do {
275    l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
276  } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
277                       
278  close(s);
279
280  msg_hdr = &rtm;
281
282  cp = ((char *)(msg_hdr + 1));
283  if (msg_hdr->rtm_addrs) {
284    for (i = 1; i; i <<= 1)
285      if (i & msg_hdr->rtm_addrs) {
286        sa = (struct sockaddr *)cp;
287        if (i == RTA_GATEWAY )
288          gate = sa;
289
290        cp += sizeof(struct sockaddr);
291      }
292  } else {
293      return FAILED;
294  }
295
296
297  if (gate != NULL ) {
298      *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr;
299      return SUCCESS;
300  } else {
301      return FAILED;
302  }
303}
304#endif /* #ifdef USE_SOCKET_ROUTE */
305
306#ifdef USE_WIN32_CODE
307LIBSPEC int getdefaultgateway(in_addr_t * addr)
308{
309        HKEY networkCardsKey;
310        HKEY networkCardKey;
311        HKEY interfacesKey;
312        HKEY interfaceKey;
313        DWORD i = 0;
314        DWORD numSubKeys = 0;
315        TCHAR keyName[MAX_KEY_LENGTH];
316        DWORD keyNameLength = MAX_KEY_LENGTH;
317        TCHAR keyValue[MAX_VALUE_LENGTH];
318        DWORD keyValueLength = MAX_VALUE_LENGTH;
319        DWORD keyValueType = REG_SZ;
320        TCHAR gatewayValue[MAX_VALUE_LENGTH];
321        DWORD gatewayValueLength = MAX_VALUE_LENGTH;
322        DWORD gatewayValueType = REG_MULTI_SZ;
323        int done = 0;
324       
325        //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
326        //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
327#ifdef UNICODE
328        LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
329        LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
330#define STR_SERVICENAME  L"ServiceName"
331#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway"
332#define STR_DEFAULTGATEWAY      L"DefaultGateway"
333#else
334        LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
335        LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
336#define STR_SERVICENAME  "ServiceName"
337#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway"
338#define STR_DEFAULTGATEWAY      "DefaultGateway"
339#endif
340        // The windows registry lists its primary network devices in the following location:
341        // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
342        //
343        // Each network device has its own subfolder, named with an index, with various properties:
344        // -NetworkCards
345        //   -5
346        //     -Description = Broadcom 802.11n Network Adapter
347        //     -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
348        //   -8
349        //     -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
350        //     -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
351        //
352        // The above service name is the name of a subfolder within:
353        // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
354        //
355        // There may be more subfolders in this interfaces path than listed in the network cards path above:
356        // -Interfaces
357        //   -{3a539854-6a70-11db-887c-806e6f6e6963}
358        //     -DhcpIPAddress = 0.0.0.0
359        //     -[more]
360        //   -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
361        //     -DhcpIPAddress = 10.0.1.4
362        //     -DhcpDefaultGateway = 10.0.1.1
363        //     -[more]
364        //   -{86226414-5545-4335-A9D1-5BD7120119AD}
365        //     -DhcpIpAddress = 10.0.1.5
366        //     -DhcpDefaultGateay = 10.0.1.1
367        //     -[more]
368        //
369        // In order to extract this information, we enumerate each network card, and extract the ServiceName value.
370        // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value.
371        // Once one is found, we're done.
372        //
373        // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value.
374        // However, the technique used is the technique most cited on the web, and we assume it to be more correct.
375       
376        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key
377                                         networkCardsPath,   // Name of registry subkey to open
378                                         0,                  // Reserved - must be zero
379                                         KEY_READ,           // Mask - desired access rights
380                                         &networkCardsKey))  // Pointer to output key
381        {
382                // Unable to open network cards keys
383                return -1;
384        }
385       
386        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key
387                                         interfacesPath,     // Name of registry subkey to open
388                                         0,                  // Reserved - must be zero
389                                         KEY_READ,           // Mask - desired access rights
390                                         &interfacesKey))    // Pointer to output key
391        {
392                // Unable to open interfaces key
393                RegCloseKey(networkCardsKey);
394                return -1;
395        }
396       
397        // Figure out how many subfolders are within the NetworkCards folder
398        RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
399       
400        //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
401       
402        // Enumrate through each subfolder within the NetworkCards folder
403        for(i = 0; i < numSubKeys && !done; i++)
404        {
405                keyNameLength = MAX_KEY_LENGTH;
406                if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key
407                                                 i,               // Index of subkey to retrieve
408                                                 keyName,         // Buffer that receives the name of the subkey
409                                                 &keyNameLength,  // Variable that receives the size of the above buffer
410                                                 NULL,            // Reserved - must be NULL
411                                                 NULL,            // Buffer that receives the class string
412                                                 NULL,            // Variable that receives the size of the above buffer
413                                                 NULL))           // Variable that receives the last write time of subkey
414                {
415                        if(RegOpenKeyEx(networkCardsKey,  keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS)
416                        {
417                                keyValueLength = MAX_VALUE_LENGTH;
418                                if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey,   // Open registry key
419                                                                    STR_SERVICENAME,    // Name of key to query
420                                                                    NULL,             // Reserved - must be NULL
421                                                                    &keyValueType,    // Receives value type
422                                                                    (LPBYTE)keyValue, // Receives value
423                                                                    &keyValueLength)) // Receives value length in bytes
424                                {
425//                                      printf("keyValue: %s\n", keyValue);                             
426                                        if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS)
427                                        {
428                                                gatewayValueLength = MAX_VALUE_LENGTH;
429                                                if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey,         // Open registry key
430                                                                                    STR_DHCPDEFAULTGATEWAY, // Name of key to query
431                                                                                    NULL,                 // Reserved - must be NULL
432                                                                                    &gatewayValueType,    // Receives value type
433                                                                                    (LPBYTE)gatewayValue, // Receives value
434                                                                                    &gatewayValueLength)) // Receives value length in bytes
435                                                {
436                                                        // Check to make sure it's a string
437                                                        if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
438                                                        {
439                                                                //printf("gatewayValue: %s\n", gatewayValue);
440                                                                done = 1;
441                                                        }
442                                                }
443                                                else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey,         // Open registry key
444                                                                                    STR_DEFAULTGATEWAY, // 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
449                                                {
450                                                        // Check to make sure it's a string
451                                                        if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
452                                                        {
453                                                                //printf("gatewayValue: %s\n", gatewayValue);
454                                                                done = 1;
455                                                        }
456                                                }
457                                                RegCloseKey(interfaceKey);
458                                        }
459                                }
460                                RegCloseKey(networkCardKey);
461                        }
462                }
463        }
464       
465        RegCloseKey(interfacesKey);
466        RegCloseKey(networkCardsKey);
467       
468        if(done)
469        {
470#if UNICODE
471                char tmp[32];
472                for(i = 0; i < 32; i++) {
473                        tmp[i] = (char)gatewayValue[i];
474                        if(!tmp[i])
475                                break;
476                }
477                tmp[31] = '\0';
478                *addr = inet_addr(tmp);
479#else
480                *addr = inet_addr(gatewayValue);
481#endif
482                return 0;
483        }
484       
485        return -1;
486}
487#endif /* #ifdef USE_WIN32_CODE */
488
489#ifdef USE_WIN32_CODE_2
490int getdefaultgateway(in_addr_t *addr)
491{
492        MIB_IPFORWARDROW ip_forward;
493        memset(&ip_forward, 0, sizeof(ip_forward));
494        if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR)
495                return -1;
496        *addr = ip_forward.dwForwardNextHop;
497        return 0;
498}
499#endif /* #ifdef USE_WIN32_CODE_2 */
500
501#ifdef USE_HAIKU_CODE
502int getdefaultgateway(in_addr_t *addr)
503{
504    int fd, ret = -1;
505    struct ifconf config;
506    void *buffer = NULL;
507    struct ifreq *interface;
508
509    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
510        return -1;
511    }
512    if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) {
513        goto fail;
514    }
515    if (config.ifc_value < 1) {
516        goto fail; /* No routes */
517    }
518    if ((buffer = malloc(config.ifc_value)) == NULL) {
519        goto fail;
520    }
521    config.ifc_len = config.ifc_value;
522    config.ifc_buf = buffer;
523    if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) {
524        goto fail;
525    }
526    for (interface = buffer;
527      (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) {
528        struct route_entry route = interface->ifr_route;
529        int intfSize;
530        if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) {
531            *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr;
532            ret = 0;
533            break;
534        }
535        intfSize = sizeof(route) + IF_NAMESIZE;
536        if (route.destination != NULL) {
537            intfSize += route.destination->sa_len;
538        }
539        if (route.mask != NULL) {
540            intfSize += route.mask->sa_len;
541        }
542        if (route.gateway != NULL) {
543            intfSize += route.gateway->sa_len;
544        }
545        interface = (struct ifreq *)((uint8_t *)interface + intfSize);
546    }
547fail:
548    free(buffer);
549    close(fd);
550    return ret;
551}
552#endif /* #ifdef USE_HAIKU_CODE */
553
554
Note: See TracBrowser for help on using the repository browser.