Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
34 static char *RCSSTRING __UNUSED__="$Id: addrs.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
36 #include <csi_platform.h>
37 #include <assert.h>
38 #include <string.h>
40 #ifdef WIN32
41 #include <winsock2.h>
42 #include <iphlpapi.h>
43 #include <tchar.h>
44 #else /* UNIX */
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #ifndef ANDROID
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50 #else
51 #include <syslog.h>
52 /* Work around an Android NDK < r8c bug */
53 #undef __unused
54 #include <linux/sysctl.h>
55 #endif
56 #include <net/if.h>
57 #ifndef LINUX
58 #if !defined(__OpenBSD__) && !defined(__NetBSD__)
59 #include <net/if_var.h>
60 #endif
61 #include <net/if_dl.h>
62 #include <net/if_types.h>
63 #include <sys/sockio.h>
64 #else
65 #include <linux/sockios.h>
66 #include <linux/if.h>
67 #include <linux/kernel.h>
68 #include <linux/wireless.h>
69 #ifndef ANDROID
70 #include <linux/ethtool.h>
71 #endif
72 #endif
73 #include <net/route.h>
75 /* IP */
76 #include <netinet/in.h>
77 #ifdef LINUX
78 #include "sys/ioctl.h"
79 #else
80 #include <netinet/in_var.h>
81 #endif
82 #include <arpa/inet.h>
83 #include <netdb.h>
84 #endif /* UNIX */
86 #include "stun.h"
87 #include "addrs.h"
91 #if defined(BSD) || defined(DARWIN)
92 /*
93 * Copyright (c) 1983, 1993
94 * The Regents of the University of California. All rights reserved.
95 *
96 * Redistribution and use in source and binary forms, with or without
97 * modification, are permitted provided that the following conditions
98 * are met:
99 * 1. Redistributions of source code must retain the above copyright
100 * notice, this list of conditions and the following disclaimer.
101 * 2. Redistributions in binary form must reproduce the above copyright
102 * notice, this list of conditions and the following disclaimer in the
103 * documentation and/or other materials provided with the distribution.
104 *[3 Deleted as of 22nd July 1999; see
105 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
106 * for details]
107 * 4. Neither the name of the University nor the names of its contributors
108 * may be used to endorse or promote products derived from this software
109 * without specific prior written permission.
110 *
111 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
112 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
113 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
114 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
115 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
116 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
117 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
118 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
119 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
120 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
121 * SUCH DAMAGE.
122 */
124 #include <err.h>
126 static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
127 static int stun_grab_addrs(char *name, int addrcount,
128 struct ifa_msghdr *ifam,
129 nr_local_addr addrs[], int maxaddrs, int *count);
130 static int
131 nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
134 /*
135 * Expand the compacted form of addresses as returned via the
136 * configuration read via sysctl().
137 */
138 #define ROUNDUP(a) \
139 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
140 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
142 static void
143 stun_rt_xaddrs(cp, cplim, rtinfo)
144 caddr_t cp, cplim;
145 struct rt_addrinfo *rtinfo;
146 {
147 struct sockaddr *sa;
148 int i;
150 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
151 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
152 if ((rtinfo->rti_addrs & (1 << i)) == 0)
153 continue;
154 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
155 ADVANCE(cp, sa);
156 }
157 }
159 static int
160 stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count)
161 {
162 int r,_status;
163 int s = -1;
164 struct ifreq ifr;
165 struct rt_addrinfo info;
166 struct sockaddr_in *sin;
168 ifr.ifr_addr.sa_family = AF_INET;
169 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
171 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
172 r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket");
173 ABORT(R_FAILED);
174 }
176 while (addrcount > 0) {
177 info.rti_addrs = ifam->ifam_addrs;
179 /* Expand the compacted addresses */
180 stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
181 addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
182 addrs[*count].interface.estimated_speed = 0;
183 /* TODO (Bug 895790) Get interface properties for Darwin */
185 switch (info.rti_info[RTAX_IFA]->sa_family) {
186 case AF_INET:
187 sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
189 if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr))))
190 ABORT(r);
192 strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname));
194 ++*count;
195 break;
196 case AF_INET6:
197 UNIMPLEMENTED;
198 break;
199 }
201 addrcount--;
203 if (*count >= maxaddrs) {
204 r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount);
205 break;
206 }
208 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
209 }
211 _status = 0;
212 abort:
213 if (s != -1) close(s);
214 return _status;
215 }
217 static int
218 stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
219 {
220 int _status;
221 char name[32];
222 int flags;
223 int addrcount;
224 struct if_msghdr *ifm, *nextifm;
225 struct ifa_msghdr *ifam;
226 struct sockaddr_dl *sdl;
227 char *buf = 0;
228 char *lim;
229 char *next;
230 size_t needed;
231 int mib[6];
233 *count = 0;
235 mib[0] = CTL_NET;
236 mib[1] = PF_ROUTE;
237 mib[2] = 0;
238 mib[3] = AF_INET;
239 mib[4] = NET_RT_IFLIST;
240 mib[5] = 0;
242 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
243 errx(1, "iflist-sysctl-estimate");
244 if ((buf = malloc(needed)) == NULL)
245 errx(1, "malloc");
246 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
247 errx(1, "actual retrieval of interface table");
248 lim = buf + needed;
250 next = buf;
251 while (next < lim) {
252 ifm = (struct if_msghdr *)next;
254 if (ifm->ifm_type == RTM_IFINFO) {
255 sdl = (struct sockaddr_dl *)(ifm + 1);
256 flags = ifm->ifm_flags;
257 } else {
258 r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
259 r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
260 ABORT(R_FAILED);
261 }
263 next += ifm->ifm_msglen;
264 ifam = NULL;
265 addrcount = 0;
266 while (next < lim) {
268 nextifm = (struct if_msghdr *)next;
270 if (nextifm->ifm_type != RTM_NEWADDR)
271 break;
273 if (ifam == NULL)
274 ifam = (struct ifa_msghdr *)nextifm;
276 addrcount++;
277 next += nextifm->ifm_msglen;
278 }
280 if (sdl->sdl_nlen > sizeof(name) - 1) {
281 ABORT(R_INTERNAL);
282 }
284 memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
285 name[sdl->sdl_nlen] = '\0';
287 stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
288 }
290 _status = 0;
291 abort:
292 if (buf) free(buf);
293 return _status;
294 }
296 #elif defined(WIN32)
298 #define WIN32_MAX_NUM_INTERFACES 20
301 #define _NR_MAX_KEY_LENGTH 256
302 #define _NR_MAX_NAME_LENGTH 512
304 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
306 static int nr_win32_get_adapter_friendly_name(char *adapter_GUID, char **friendly_name)
307 {
308 int r,_status;
309 HKEY adapter_reg;
310 TCHAR adapter_key[_NR_MAX_KEY_LENGTH];
311 TCHAR keyval_buf[_NR_MAX_KEY_LENGTH];
312 TCHAR adapter_GUID_tchar[_NR_MAX_NAME_LENGTH];
313 DWORD keyval_len, key_type;
314 size_t converted_chars, newlen;
315 char *my_fn = 0;
317 #ifdef _UNICODE
318 mbstowcs_s(&converted_chars, adapter_GUID_tchar, strlen(adapter_GUID)+1,
319 adapter_GUID, _TRUNCATE);
320 #else
321 strlcpy(adapter_GUID_tchar, adapter_GUID, _NR_MAX_NAME_LENGTH);
322 #endif
324 _tcscpy_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT(_ADAPTERS_BASE_REG));
325 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\"));
326 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, adapter_GUID_tchar);
327 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\Connection"));
329 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg);
331 if (r != ERROR_SUCCESS) {
332 r_log(NR_LOG_STUN, LOG_ERR, "Got error %d opening adapter reg key\n", r);
333 ABORT(R_INTERNAL);
334 }
336 keyval_len = sizeof(keyval_buf);
337 r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type,
338 (BYTE *)keyval_buf, &keyval_len);
340 RegCloseKey(adapter_reg);
342 #ifdef UNICODE
343 newlen = wcslen(keyval_buf)+1;
344 my_fn = (char *) RCALLOC(newlen);
345 if (!my_fn) {
346 ABORT(R_NO_MEMORY);
347 }
348 wcstombs_s(&converted_chars, my_fn, newlen, keyval_buf, _TRUNCATE);
349 #else
350 my_fn = r_strdup(keyval_buf);
351 #endif
353 *friendly_name = my_fn;
354 _status=0;
356 abort:
357 if (_status) {
358 if (my_fn) free(my_fn);
359 }
360 return(_status);
361 }
364 static int
365 stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
366 {
367 int r,_status;
368 PIP_ADAPTER_INFO pAdapterInfo;
369 PIP_ADAPTER_INFO pAdapter = NULL;
370 PIP_ADDR_STRING pAddrString;
371 ULONG out_buf_len;
372 char *friendly_name=0;
373 char munged_ifname[IFNAMSIZ];
374 int n = 0;
376 *count = 0;
378 pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
379 out_buf_len = sizeof(IP_ADAPTER_INFO);
381 /* First call to GetAdaptersInfo is mainly to get length */
383 if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
384 RFREE(pAdapterInfo);
385 pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
386 if (pAdapterInfo == NULL) {
387 r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
388 ABORT(R_NO_MEMORY);
389 }
390 }
391 if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
392 r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
393 ABORT(R_INTERNAL);
394 }
395 r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
397 pAdapter = pAdapterInfo;
399 while (pAdapter) {
400 char *c;
402 r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
403 r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
405 if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) {
406 friendly_name = 0;
407 }
408 if (friendly_name && *friendly_name) {
409 r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
410 snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
411 RFREE(friendly_name);
412 friendly_name = 0;
413 } else {
414 // Not all adapters follow the friendly name convention. Windows' PPTP
415 // VPN adapter puts "VPN Connection 2" in the Description field instead.
416 // Windows's renaming-logic appears to enforce uniqueness in spite of this.
417 r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description);
418 snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0);
419 }
420 /* replace spaces with underscores */
421 c = strchr(munged_ifname, ' ');
422 while (c != NULL) {
423 *c = '_';
424 c = strchr(munged_ifname, ' ');
425 }
426 c = strchr(munged_ifname, '.');
427 while (c != NULL) {
428 *c = '+';
429 c = strchr(munged_ifname, '.');
430 }
432 r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
434 for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
435 unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
436 nr_transport_addr *addr = &(addrs[n].addr);
438 if (this_addr == 0)
439 continue;
441 r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
443 addr->ip_version=NR_IPV4;
444 addr->protocol = IPPROTO_UDP;
446 addr->u.addr4.sin_family=PF_INET;
447 addr->u.addr4.sin_port=0;
448 addr->u.addr4.sin_addr.s_addr=this_addr;
449 addr->addr=(struct sockaddr *)&(addr->u.addr4);
450 addr->addr_len=sizeof(struct sockaddr_in);
452 strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname));
453 snprintf(addr->as_string,40,"IP4:%s:%d",
454 inet_ntoa(addr->u.addr4.sin_addr),
455 ntohs(addr->u.addr4.sin_port));
457 /* TODO: (Bug 895793) Getting interface properties for Windows */
458 addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
459 addrs[n].interface.estimated_speed = 0;
461 if (++n >= maxaddrs)
462 goto done;
463 }
465 pAdapter = pAdapter->Next;
466 }
468 done:
469 *count = n;
470 _status = 0;
472 abort:
473 RFREE(pAdapterInfo);
474 RFREE(friendly_name);
475 return _status;
476 }
478 #ifdef GET_WIN32_ADDRS_NO_WIN2K
479 /* Here's a nice way to get adapter addresses and names, but it
480 * isn't supported on Win2000.
481 */
482 static int
483 stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
484 {
485 int r,_status;
486 PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
487 ULONG buflen;
488 char munged_ifname[IFNAMSIZ];
489 int n = 0;
491 *count = 0;
493 if (maxaddrs <= 0)
494 ABORT(R_INTERNAL);
496 /* Call GetAdaptersAddresses() twice. First, just to get the buf length */
498 buflen = 0;
500 r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
501 if (r != ERROR_BUFFER_OVERFLOW) {
502 r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
503 ABORT(R_INTERNAL);
504 }
506 AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
507 if (AdapterAddresses == NULL) {
508 r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
509 ABORT(R_NO_MEMORY);
510 }
512 /* for real, this time */
514 r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
515 if (r != NO_ERROR) {
516 r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
517 ABORT(R_INTERNAL);
518 }
520 /* Loop through the adapters */
522 for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
523 char *c;
525 if (tmpAddress->OperStatus != IfOperStatusUp)
526 continue;
528 snprintf(munged_ifname, IFNAMSIZ, "%S%c", tmpAddress->FriendlyName, 0);
529 /* replace spaces with underscores */
530 c = strchr(munged_ifname, ' ');
531 while (c != NULL) {
532 *c = '_';
533 c = strchr(munged_ifname, ' ');
534 }
535 c = strchr(munged_ifname, '.');
536 while (c != NULL) {
537 *c = '+';
538 c = strchr(munged_ifname, '+');
539 }
541 if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
542 IP_ADAPTER_UNICAST_ADDRESS *u = 0;
544 for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
545 SOCKET_ADDRESS *sa_addr = &u->Address;
547 if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
548 (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
549 if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr))))
550 ABORT(r);
551 }
552 else {
553 r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname);
554 continue;
555 }
557 strlcpy(addrs[n].addr.ifname, munged_ifname, sizeof(addrs[n].addr.ifname));
558 /* TODO: (Bug 895793) Getting interface properties for Windows */
559 addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
560 addrs[n].interface.estimated_speed = 0;
561 if (++n >= maxaddrs)
562 goto done;
563 }
564 }
565 }
567 done:
568 *count = n;
569 _status = 0;
571 abort:
572 RFREE(AdapterAddresses);
573 return _status;
574 }
575 #endif /* GET_WIN32_ADDRS_NO_WIN2K */
577 #elif defined(__sparc__)
579 static int
580 stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
581 {
582 *count = 0;
583 UNIMPLEMENTED; /*TODO !nn! - sparc */
584 return 0;
585 }
587 #else
589 static int
590 stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
591 {
592 struct ifconf ifc;
593 int _status;
594 int s = socket( AF_INET, SOCK_DGRAM, 0 );
595 int len = 100 * sizeof(struct ifreq);
596 int r;
597 int e;
598 char *ptr;
599 int tl;
600 int n;
601 struct ifreq ifr2;
603 char buf[ len ];
605 ifc.ifc_len = len;
606 ifc.ifc_buf = buf;
608 e = ioctl(s,SIOCGIFCONF,&ifc);
609 ptr = buf;
610 tl = ifc.ifc_len;
611 n=0;
613 while ( (tl > 0) && ( n < maxaddrs) )
614 {
615 struct ifreq* ifr = (struct ifreq *)ptr;
617 #ifdef LINUX
618 int si = sizeof(struct ifreq);
619 #ifndef ANDROID
620 struct ethtool_cmd ecmd;
621 struct iwreq wrq;
622 #endif
623 #else
624 int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
625 #endif
626 tl -= si;
627 ptr += si;
629 ifr2 = *ifr;
631 e = ioctl(s,SIOCGIFADDR,&ifr2);
632 if ( e == -1 )
633 {
634 continue;
635 }
637 //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
639 if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) {
640 r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
641 }
642 else {
643 addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
644 addrs[n].interface.estimated_speed = 0;
645 #if defined(LINUX) && !defined(ANDROID)
646 /* TODO (Bug 896851): interface property for Android */
647 /* Getting ethtool for ethernet information. */
648 ecmd.cmd = ETHTOOL_GSET;
649 ifr2.ifr_data = (void*)&ecmd;
650 e = ioctl(s, SIOCETHTOOL, &ifr2);
651 if (e == 0)
652 {
653 /* For wireless network, we won't get ethtool, it's a wired
654 connection */
655 addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
656 #ifdef DONT_HAVE_ETHTOOL_SPEED_HI
657 addrs[n].interface.estimated_speed = ecmd.speed;
658 #else
659 addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
660 #endif
661 }
663 strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name));
664 e = ioctl(s, SIOCGIWRATE, &wrq);
665 if (e == 0)
666 {
667 addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
668 addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000;
669 }
671 ifr2 = *ifr;
672 e = ioctl(s, SIOCGIFFLAGS, &ifr2);
673 if (e == 0)
674 {
675 if (ifr2.ifr_flags & IFF_POINTOPOINT)
676 {
677 addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
678 /* TODO (Bug 896913): find backend network type of this VPN */
679 }
680 }
681 #endif
682 strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname));
683 ++n;
684 }
685 }
687 close(s);
689 *count = n;
691 _status = 0;
692 return _status;
693 }
694 #endif
696 static int
697 nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
698 {
699 int i;
700 int different;
702 for (i = 0; i < count; ++i) {
703 different = nr_transport_addr_cmp(&addrs[i].addr, &(addr->addr),
704 NR_TRANSPORT_ADDR_CMP_MODE_ALL);
705 if (!different)
706 return 1; /* duplicate */
707 }
709 return 0;
710 }
712 int
713 nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count)
714 {
715 int r, _status;
716 nr_local_addr *tmp = 0;
717 int i;
718 int n;
720 tmp = RMALLOC(*count * sizeof(*tmp));
721 if (!tmp)
722 ABORT(R_NO_MEMORY);
724 n = 0;
725 for (i = 0; i < *count; ++i) {
726 if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
727 /* skip addrs[i], it's a duplicate */
728 }
729 else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
730 /* skip addrs[i], it's a loopback */
731 }
732 else {
733 /* otherwise, copy it to the temporary array */
734 if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
735 ABORT(r);
736 ++n;
737 }
738 }
740 *count = n;
742 /* copy temporary array into passed in/out array */
743 for (i = 0; i < *count; ++i) {
744 if ((r=nr_local_addr_copy(&addrs[i], &tmp[i])))
745 ABORT(r);
746 }
748 _status = 0;
749 abort:
750 RFREE(tmp);
751 return _status;
752 }
754 #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
756 int
757 nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count)
758 {
759 int _status=0;
760 int i;
761 char typestr[100];
763 #if defined(BSD) || defined(DARWIN)
764 _status = stun_get_mib_addrs(addrs, maxaddrs, count);
765 #elif defined(WIN32)
766 _status = stun_get_win32_addrs(addrs, maxaddrs, count);
767 #elif defined(__sparc__)
768 _status = stun_get_sparc_addrs(addrs, maxaddrs, count);
769 #else
770 _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
771 #endif
773 nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
775 for (i = 0; i < *count; ++i) {
776 nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
777 r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
778 i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
779 }
781 return _status;
782 }
784 #endif