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

Last change on this file since 6706 was 6706, checked in by muks, 13 years ago

(win32) Add includes for natpmp

File size: 12.4 KB
Line 
1/* $Id: getgateway.c,v 1.11 2008/07/02 23:56:11 nanard Exp $ */
2/* libnatpmp
3 * Copyright (c) 2007-2008, 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#else
21#include <winsock2.h>
22#include <ws2tcpip.h>
23#endif
24#include <sys/param.h>
25/* There is no portable method to get the default route gateway.
26 * So below are three differents functions implementing this.
27 * Parsing /proc/net/route is for linux.
28 * sysctl is the way to access such informations on BSD systems.
29 * Many systems should provide route information through raw PF_ROUTE
30 * sockets. */
31#ifdef __linux__
32#define USE_PROC_NET_ROUTE
33#undef USE_SOCKET_ROUTE
34#undef USE_SYSCTL_NET_ROUTE
35#endif
36
37#ifdef BSD
38#undef USE_PROC_NET_ROUTE
39#define USE_SOCKET_ROUTE
40#undef USE_SYSCTL_NET_ROUTE
41#endif
42
43#ifdef __APPLE__
44#undef USE_PROC_NET_ROUTE
45#undef USE_SOCKET_ROUTE
46#define USE_SYSCTL_NET_ROUTE
47#endif
48
49#if (defined(sun) && defined(__SVR4))
50#undef USE_PROC_NET_ROUTE
51#define USE_SOCKET_ROUTE
52#undef USE_SYSCTL_NET_ROUTE
53#endif
54
55#ifdef WIN32
56#undef USE_PROC_NET_ROUTE
57#undef USE_SOCKET_ROUTE
58#undef USE_SYSCTL_NET_ROUTE
59#define USE_WIN32_CODE
60#endif
61
62#ifdef USE_SYSCTL_NET_ROUTE
63#include <stdlib.h>
64#include <sys/sysctl.h>
65#include <sys/socket.h>
66#include <net/route.h>
67#endif
68#ifdef USE_SOCKET_ROUTE
69#include <unistd.h>
70#include <string.h>
71#include <sys/socket.h>
72#include <net/if.h>
73#include <net/route.h>
74#endif
75#ifdef WIN32
76#include <unknwn.h>
77#include <winreg.h>
78#define MAX_KEY_LENGTH 255
79#define MAX_VALUE_LENGTH 16383
80#endif
81#include "getgateway.h"
82
83#ifndef WIN32
84#define SUCCESS (0)
85#define FAILED  (-1)
86#endif
87
88#ifdef USE_PROC_NET_ROUTE
89int getdefaultgateway(in_addr_t * addr)
90{
91        long d, g;
92        char buf[256];
93        int line = 0;
94        FILE * f;
95        char * p;
96        f = fopen("/proc/net/route", "r");
97        if(!f)
98                return FAILED;
99        while(fgets(buf, sizeof(buf), f)) {
100                if(line > 0) {
101                        p = buf;
102                        while(*p && !isspace(*p))
103                                p++;
104                        while(*p && isspace(*p))
105                                p++;
106                        if(sscanf(p, "%lx%lx", &d, &g)==2) {
107                                if(d == 0) { /* default */
108                                        *addr = g;
109                                        fclose(f);
110                                        return SUCCESS;
111                                }
112                        }
113                }
114                line++;
115        }
116        /* default route not found ! */
117        if(f)
118                fclose(f);
119        return FAILED;
120}
121#endif /* #ifdef USE_PROC_NET_ROUTE */
122
123
124#ifdef USE_SYSCTL_NET_ROUTE
125
126#define ROUNDUP(a) \
127        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
128
129int getdefaultgateway(in_addr_t * addr)
130{
131#if 0
132        /* net.route.0.inet.dump.0.0 ? */
133        int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
134                     NET_RT_DUMP, 0, 0/*tableid*/};
135#endif
136        /* net.route.0.inet.flags.gateway */
137        int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
138                     NET_RT_FLAGS, RTF_GATEWAY};
139        size_t l;
140        char * buf, * p;
141        struct rt_msghdr * rt;
142        struct sockaddr * sa;
143        struct sockaddr * sa_tab[RTAX_MAX];
144        int i;
145        int r = FAILED;
146        if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
147                return FAILED;
148        }
149        if(l>0) {
150                buf = malloc(l);
151                if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
152                        return FAILED;
153                }
154                for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
155                        rt = (struct rt_msghdr *)p;
156                        sa = (struct sockaddr *)(rt + 1);
157                        for(i=0; i<RTAX_MAX; i++) {
158                                if(rt->rtm_addrs & (1 << i)) {
159                                        sa_tab[i] = sa;
160                                        sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
161                                } else {
162                                        sa_tab[i] = NULL;
163                                }
164                        }
165                        if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
166              && sa_tab[RTAX_DST]->sa_family == AF_INET
167              && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
168                                if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
169                                        *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
170                                        r = SUCCESS;
171                                }
172                        }
173                }
174                free(buf);
175        }
176        return r;
177}
178#endif /* #ifdef USE_SYSCTL_NET_ROUTE */
179
180
181#ifdef USE_SOCKET_ROUTE
182/* Thanks to Darren Kenny for this code */
183#define NEXTADDR(w, u) \
184        if (rtm_addrs & (w)) {\
185            l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
186        }
187
188#define rtm m_rtmsg.m_rtm
189
190struct {
191  struct rt_msghdr m_rtm;
192  char       m_space[512];
193} m_rtmsg;
194
195int getdefaultgateway(in_addr_t *addr)
196{
197  int s, seq, l, rtm_addrs, i;
198  pid_t pid;
199  struct sockaddr so_dst, so_mask;
200  char *cp = m_rtmsg.m_space; 
201  struct sockaddr *gate = NULL, *sa;
202  struct rt_msghdr *msg_hdr;
203
204  pid = getpid();
205  seq = 0;
206  rtm_addrs = RTA_DST | RTA_NETMASK;
207
208  memset(&so_dst, 0, sizeof(so_dst));
209  memset(&so_mask, 0, sizeof(so_mask));
210  memset(&rtm, 0, sizeof(struct rt_msghdr));
211
212  rtm.rtm_type = RTM_GET;
213  rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
214  rtm.rtm_version = RTM_VERSION;
215  rtm.rtm_seq = ++seq;
216  rtm.rtm_addrs = rtm_addrs; 
217
218  so_dst.sa_family = AF_INET;
219  so_mask.sa_family = AF_INET;
220
221  NEXTADDR(RTA_DST, so_dst);
222  NEXTADDR(RTA_NETMASK, so_mask);
223
224  rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
225
226  s = socket(PF_ROUTE, SOCK_RAW, 0);
227
228  if (write(s, (char *)&m_rtmsg, l) < 0) {
229      close(s);
230      return FAILED;
231  }
232
233  do {
234    l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
235  } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
236                       
237  close(s);
238
239  msg_hdr = &rtm;
240
241  cp = ((char *)(msg_hdr + 1));
242  if (msg_hdr->rtm_addrs) {
243    for (i = 1; i; i <<= 1)
244      if (i & msg_hdr->rtm_addrs) {
245        sa = (struct sockaddr *)cp;
246        if (i == RTA_GATEWAY )
247          gate = sa;
248
249        cp += sizeof(struct sockaddr);
250      }
251  } else {
252      return FAILED;
253  }
254
255
256  if (gate != NULL ) {
257      *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr;
258      return SUCCESS;
259  } else {
260      return FAILED;
261  }
262}
263#endif /* #ifdef USE_SOCKET_ROUTE */
264
265#ifdef USE_WIN32_CODE
266int getdefaultgateway(in_addr_t * addr)
267{
268        HKEY networkCardsKey;
269        HKEY networkCardKey;
270        HKEY interfacesKey;
271        HKEY interfaceKey;
272        DWORD i = 0;
273        DWORD numSubKeys = 0;
274        TCHAR keyName[MAX_KEY_LENGTH];
275        DWORD keyNameLength = MAX_KEY_LENGTH;
276        TCHAR keyValue[MAX_VALUE_LENGTH];
277        DWORD keyValueLength = MAX_VALUE_LENGTH;
278        DWORD keyValueType = REG_SZ;
279        TCHAR gatewayValue[MAX_VALUE_LENGTH];
280        DWORD gatewayValueLength = MAX_VALUE_LENGTH;
281        DWORD gatewayValueType = REG_MULTI_SZ;
282        int done = 0;
283       
284        char networkCardsPath[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
285        char interfacesPath[] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
286       
287        // The windows registry lists its primary network devices in the following location:
288        // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
289        //
290        // Each network device has its own subfolder, named with an index, with various properties:
291        // -NetworkCards
292        //   -5
293        //     -Description = Broadcom 802.11n Network Adapter
294        //     -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
295        //   -8
296        //     -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
297        //     -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
298        //
299        // The above service name is the name of a subfolder within:
300        // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
301        //
302        // There may be more subfolders in this interfaces path than listed in the network cards path above:
303        // -Interfaces
304        //   -{3a539854-6a70-11db-887c-806e6f6e6963}
305        //     -DhcpIPAddress = 0.0.0.0
306        //     -[more]
307        //   -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
308        //     -DhcpIPAddress = 10.0.1.4
309        //     -DhcpDefaultGateway = 10.0.1.1
310        //     -[more]
311        //   -{86226414-5545-4335-A9D1-5BD7120119AD}
312        //     -DhcpIpAddress = 10.0.1.5
313        //     -DhcpDefaultGateay = 10.0.1.1
314        //     -[more]
315        //
316        // In order to extract this information, we enumerate each network card, and extract the ServiceName value.
317        // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value.
318        // Once one is found, we're done.
319        //
320        // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value.
321        // However, the technique used is the technique most cited on the web, and we assume it to be more correct.
322       
323        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key
324                                         networkCardsPath,   // Name of registry subkey to open
325                                         0,                  // Reserved - must be zero
326                                         KEY_READ,           // Mask - desired access rights
327                                         &networkCardsKey))  // Pointer to output key
328        {
329                // Unable to open network cards keys
330                return -1;
331        }
332       
333        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key
334                                         interfacesPath,     // Name of registry subkey to open
335                                         0,                  // Reserved - must be zero
336                                         KEY_READ,           // Mask - desired access rights
337                                         &interfacesKey))    // Pointer to output key
338        {
339                // Unable to open interfaces key
340                RegCloseKey(networkCardsKey);
341                return -1;
342        }
343       
344        // Figure out how many subfolders are within the NetworkCards folder
345        RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
346       
347        //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
348       
349        // Enumrate through each subfolder within the NetworkCards folder
350        for(i = 0; i < numSubKeys && !done; i++)
351        {
352                keyNameLength = MAX_KEY_LENGTH;
353                if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key
354                                                 i,               // Index of subkey to retrieve
355                                                 keyName,         // Buffer that receives the name of the subkey
356                                                 &keyNameLength,  // Variable that receives the size of the above buffer
357                                                 NULL,            // Reserved - must be NULL
358                                                 NULL,            // Buffer that receives the class string
359                                                 NULL,            // Variable that receives the size of the above buffer
360                                                 NULL))           // Variable that receives the last write time of subkey
361                {
362                        if(RegOpenKeyEx(networkCardsKey,  keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS)
363                        {
364                                keyValueLength = MAX_VALUE_LENGTH;
365                                if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey,   // Open registry key
366                                                                    "ServiceName",    // Name of key to query
367                                                                    NULL,             // Reserved - must be NULL
368                                                                    &keyValueType,    // Receives value type
369                                                                    keyValue,         // Receives value
370                                                                    &keyValueLength)) // Receives value length in bytes
371                                {
372                                        //printf("keyValue: %s\n", keyValue);
373                                       
374                                        if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS)
375                                        {
376                                                gatewayValueLength = MAX_VALUE_LENGTH;
377                                                if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey,         // Open registry key
378                                                                                    "DhcpDefaultGateway", // Name of key to query
379                                                                                    NULL,                 // Reserved - must be NULL
380                                                                                    &gatewayValueType,    // Receives value type
381                                                                                    gatewayValue,         // Receives value
382                                                                                    &gatewayValueLength)) // Receives value length in bytes
383                                                {
384                                                        // Check to make sure it's a string
385                                                        if(gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ)
386                                                        {
387                                                                //printf("gatewayValue: %s\n", gatewayValue);
388                                                                done = 1;
389                                                        }
390                                                }
391                                                RegCloseKey(interfaceKey);
392                                        }
393                                }
394                                RegCloseKey(networkCardKey);
395                        }
396                }
397        }
398       
399        RegCloseKey(interfacesKey);
400        RegCloseKey(networkCardsKey);
401       
402        if(done)
403        {
404                *addr = inet_addr(gatewayValue);
405                return 0;
406        }
407       
408        return -1;
409}
410#endif /* #ifdef USE_WIN32_CODE */
411
Note: See TracBrowser for help on using the repository browser.