media/mtransport/third_party/nICEr/src/stun/addrs.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial