michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: michael@0: static char *RCSSTRING __UNUSED__="$Id: addrs.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #include michael@0: #include michael@0: #else /* UNIX */ michael@0: #include michael@0: #include michael@0: #ifndef ANDROID michael@0: #include michael@0: #include michael@0: #else michael@0: #include michael@0: /* Work around an Android NDK < r8c bug */ michael@0: #undef __unused michael@0: #include michael@0: #endif michael@0: #include michael@0: #ifndef LINUX michael@0: #if !defined(__OpenBSD__) && !defined(__NetBSD__) michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: #else michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #ifndef ANDROID michael@0: #include michael@0: #endif michael@0: #endif michael@0: #include michael@0: michael@0: /* IP */ michael@0: #include michael@0: #ifdef LINUX michael@0: #include "sys/ioctl.h" michael@0: #else michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #endif /* UNIX */ michael@0: michael@0: #include "stun.h" michael@0: #include "addrs.h" michael@0: michael@0: michael@0: michael@0: #if defined(BSD) || defined(DARWIN) michael@0: /* michael@0: * Copyright (c) 1983, 1993 michael@0: * The Regents of the University of California. All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: *[3 Deleted as of 22nd July 1999; see michael@0: * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change michael@0: * for details] michael@0: * 4. Neither the name of the University nor the names of its contributors michael@0: * may be used to endorse or promote products derived from this software michael@0: * without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND michael@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE michael@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE michael@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL michael@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS michael@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) michael@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT michael@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY michael@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF michael@0: * SUCH DAMAGE. michael@0: */ michael@0: michael@0: #include michael@0: michael@0: static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); michael@0: static int stun_grab_addrs(char *name, int addrcount, michael@0: struct ifa_msghdr *ifam, michael@0: nr_local_addr addrs[], int maxaddrs, int *count); michael@0: static int michael@0: nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr); michael@0: michael@0: michael@0: /* michael@0: * Expand the compacted form of addresses as returned via the michael@0: * configuration read via sysctl(). michael@0: */ michael@0: #define ROUNDUP(a) \ michael@0: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) michael@0: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) michael@0: michael@0: static void michael@0: stun_rt_xaddrs(cp, cplim, rtinfo) michael@0: caddr_t cp, cplim; michael@0: struct rt_addrinfo *rtinfo; michael@0: { michael@0: struct sockaddr *sa; michael@0: int i; michael@0: michael@0: memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); michael@0: for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { michael@0: if ((rtinfo->rti_addrs & (1 << i)) == 0) michael@0: continue; michael@0: rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; michael@0: ADVANCE(cp, sa); michael@0: } michael@0: } michael@0: michael@0: static int michael@0: stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: int r,_status; michael@0: int s = -1; michael@0: struct ifreq ifr; michael@0: struct rt_addrinfo info; michael@0: struct sockaddr_in *sin; michael@0: michael@0: ifr.ifr_addr.sa_family = AF_INET; michael@0: strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); michael@0: michael@0: if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket"); michael@0: ABORT(R_FAILED); michael@0: } michael@0: michael@0: while (addrcount > 0) { michael@0: info.rti_addrs = ifam->ifam_addrs; michael@0: michael@0: /* Expand the compacted addresses */ michael@0: stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); michael@0: addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN; michael@0: addrs[*count].interface.estimated_speed = 0; michael@0: /* TODO (Bug 895790) Get interface properties for Darwin */ michael@0: michael@0: switch (info.rti_info[RTAX_IFA]->sa_family) { michael@0: case AF_INET: michael@0: sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; michael@0: michael@0: if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr)))) michael@0: ABORT(r); michael@0: michael@0: strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname)); michael@0: michael@0: ++*count; michael@0: break; michael@0: case AF_INET6: michael@0: UNIMPLEMENTED; michael@0: break; michael@0: } michael@0: michael@0: addrcount--; michael@0: michael@0: if (*count >= maxaddrs) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount); michael@0: break; michael@0: } michael@0: michael@0: ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); michael@0: } michael@0: michael@0: _status = 0; michael@0: abort: michael@0: if (s != -1) close(s); michael@0: return _status; michael@0: } michael@0: michael@0: static int michael@0: stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: int _status; michael@0: char name[32]; michael@0: int flags; michael@0: int addrcount; michael@0: struct if_msghdr *ifm, *nextifm; michael@0: struct ifa_msghdr *ifam; michael@0: struct sockaddr_dl *sdl; michael@0: char *buf = 0; michael@0: char *lim; michael@0: char *next; michael@0: size_t needed; michael@0: int mib[6]; michael@0: michael@0: *count = 0; michael@0: michael@0: mib[0] = CTL_NET; michael@0: mib[1] = PF_ROUTE; michael@0: mib[2] = 0; michael@0: mib[3] = AF_INET; michael@0: mib[4] = NET_RT_IFLIST; michael@0: mib[5] = 0; michael@0: michael@0: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) michael@0: errx(1, "iflist-sysctl-estimate"); michael@0: if ((buf = malloc(needed)) == NULL) michael@0: errx(1, "malloc"); michael@0: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) michael@0: errx(1, "actual retrieval of interface table"); michael@0: lim = buf + needed; michael@0: michael@0: next = buf; michael@0: while (next < lim) { michael@0: ifm = (struct if_msghdr *)next; michael@0: michael@0: if (ifm->ifm_type == RTM_IFINFO) { michael@0: sdl = (struct sockaddr_dl *)(ifm + 1); michael@0: flags = ifm->ifm_flags; michael@0: } else { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST"); michael@0: 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: ABORT(R_FAILED); michael@0: } michael@0: michael@0: next += ifm->ifm_msglen; michael@0: ifam = NULL; michael@0: addrcount = 0; michael@0: while (next < lim) { michael@0: michael@0: nextifm = (struct if_msghdr *)next; michael@0: michael@0: if (nextifm->ifm_type != RTM_NEWADDR) michael@0: break; michael@0: michael@0: if (ifam == NULL) michael@0: ifam = (struct ifa_msghdr *)nextifm; michael@0: michael@0: addrcount++; michael@0: next += nextifm->ifm_msglen; michael@0: } michael@0: michael@0: if (sdl->sdl_nlen > sizeof(name) - 1) { michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: memcpy(name, sdl->sdl_data, sdl->sdl_nlen); michael@0: name[sdl->sdl_nlen] = '\0'; michael@0: michael@0: stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count); michael@0: } michael@0: michael@0: _status = 0; michael@0: abort: michael@0: if (buf) free(buf); michael@0: return _status; michael@0: } michael@0: michael@0: #elif defined(WIN32) michael@0: michael@0: #define WIN32_MAX_NUM_INTERFACES 20 michael@0: michael@0: michael@0: #define _NR_MAX_KEY_LENGTH 256 michael@0: #define _NR_MAX_NAME_LENGTH 512 michael@0: michael@0: #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" michael@0: michael@0: static int nr_win32_get_adapter_friendly_name(char *adapter_GUID, char **friendly_name) michael@0: { michael@0: int r,_status; michael@0: HKEY adapter_reg; michael@0: TCHAR adapter_key[_NR_MAX_KEY_LENGTH]; michael@0: TCHAR keyval_buf[_NR_MAX_KEY_LENGTH]; michael@0: TCHAR adapter_GUID_tchar[_NR_MAX_NAME_LENGTH]; michael@0: DWORD keyval_len, key_type; michael@0: size_t converted_chars, newlen; michael@0: char *my_fn = 0; michael@0: michael@0: #ifdef _UNICODE michael@0: mbstowcs_s(&converted_chars, adapter_GUID_tchar, strlen(adapter_GUID)+1, michael@0: adapter_GUID, _TRUNCATE); michael@0: #else michael@0: strlcpy(adapter_GUID_tchar, adapter_GUID, _NR_MAX_NAME_LENGTH); michael@0: #endif michael@0: michael@0: _tcscpy_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT(_ADAPTERS_BASE_REG)); michael@0: _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\")); michael@0: _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, adapter_GUID_tchar); michael@0: _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\Connection")); michael@0: michael@0: r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg); michael@0: michael@0: if (r != ERROR_SUCCESS) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Got error %d opening adapter reg key\n", r); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: keyval_len = sizeof(keyval_buf); michael@0: r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type, michael@0: (BYTE *)keyval_buf, &keyval_len); michael@0: michael@0: RegCloseKey(adapter_reg); michael@0: michael@0: #ifdef UNICODE michael@0: newlen = wcslen(keyval_buf)+1; michael@0: my_fn = (char *) RCALLOC(newlen); michael@0: if (!my_fn) { michael@0: ABORT(R_NO_MEMORY); michael@0: } michael@0: wcstombs_s(&converted_chars, my_fn, newlen, keyval_buf, _TRUNCATE); michael@0: #else michael@0: my_fn = r_strdup(keyval_buf); michael@0: #endif michael@0: michael@0: *friendly_name = my_fn; michael@0: _status=0; michael@0: michael@0: abort: michael@0: if (_status) { michael@0: if (my_fn) free(my_fn); michael@0: } michael@0: return(_status); michael@0: } michael@0: michael@0: michael@0: static int michael@0: stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: int r,_status; michael@0: PIP_ADAPTER_INFO pAdapterInfo; michael@0: PIP_ADAPTER_INFO pAdapter = NULL; michael@0: PIP_ADDR_STRING pAddrString; michael@0: ULONG out_buf_len; michael@0: char *friendly_name=0; michael@0: char munged_ifname[IFNAMSIZ]; michael@0: int n = 0; michael@0: michael@0: *count = 0; michael@0: michael@0: pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO)); michael@0: out_buf_len = sizeof(IP_ADAPTER_INFO); michael@0: michael@0: /* First call to GetAdaptersInfo is mainly to get length */ michael@0: michael@0: if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) { michael@0: RFREE(pAdapterInfo); michael@0: pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len); michael@0: if (pAdapterInfo == NULL) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output"); michael@0: ABORT(R_NO_MEMORY); michael@0: } michael@0: } michael@0: if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo"); michael@0: michael@0: pAdapter = pAdapterInfo; michael@0: michael@0: while (pAdapter) { michael@0: char *c; michael@0: michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName); michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description); michael@0: michael@0: if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) { michael@0: friendly_name = 0; michael@0: } michael@0: if (friendly_name && *friendly_name) { michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name); michael@0: snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0); michael@0: RFREE(friendly_name); michael@0: friendly_name = 0; michael@0: } else { michael@0: // Not all adapters follow the friendly name convention. Windows' PPTP michael@0: // VPN adapter puts "VPN Connection 2" in the Description field instead. michael@0: // Windows's renaming-logic appears to enforce uniqueness in spite of this. michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description); michael@0: snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0); michael@0: } michael@0: /* replace spaces with underscores */ michael@0: c = strchr(munged_ifname, ' '); michael@0: while (c != NULL) { michael@0: *c = '_'; michael@0: c = strchr(munged_ifname, ' '); michael@0: } michael@0: c = strchr(munged_ifname, '.'); michael@0: while (c != NULL) { michael@0: *c = '+'; michael@0: c = strchr(munged_ifname, '.'); michael@0: } michael@0: michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname); michael@0: michael@0: for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) { michael@0: unsigned long this_addr = inet_addr(pAddrString->IpAddress.String); michael@0: nr_transport_addr *addr = &(addrs[n].addr); michael@0: michael@0: if (this_addr == 0) michael@0: continue; michael@0: michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String); michael@0: michael@0: addr->ip_version=NR_IPV4; michael@0: addr->protocol = IPPROTO_UDP; michael@0: michael@0: addr->u.addr4.sin_family=PF_INET; michael@0: addr->u.addr4.sin_port=0; michael@0: addr->u.addr4.sin_addr.s_addr=this_addr; michael@0: addr->addr=(struct sockaddr *)&(addr->u.addr4); michael@0: addr->addr_len=sizeof(struct sockaddr_in); michael@0: michael@0: strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname)); michael@0: snprintf(addr->as_string,40,"IP4:%s:%d", michael@0: inet_ntoa(addr->u.addr4.sin_addr), michael@0: ntohs(addr->u.addr4.sin_port)); michael@0: michael@0: /* TODO: (Bug 895793) Getting interface properties for Windows */ michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN; michael@0: addrs[n].interface.estimated_speed = 0; michael@0: michael@0: if (++n >= maxaddrs) michael@0: goto done; michael@0: } michael@0: michael@0: pAdapter = pAdapter->Next; michael@0: } michael@0: michael@0: done: michael@0: *count = n; michael@0: _status = 0; michael@0: michael@0: abort: michael@0: RFREE(pAdapterInfo); michael@0: RFREE(friendly_name); michael@0: return _status; michael@0: } michael@0: michael@0: #ifdef GET_WIN32_ADDRS_NO_WIN2K michael@0: /* Here's a nice way to get adapter addresses and names, but it michael@0: * isn't supported on Win2000. michael@0: */ michael@0: static int michael@0: stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: int r,_status; michael@0: PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL; michael@0: ULONG buflen; michael@0: char munged_ifname[IFNAMSIZ]; michael@0: int n = 0; michael@0: michael@0: *count = 0; michael@0: michael@0: if (maxaddrs <= 0) michael@0: ABORT(R_INTERNAL); michael@0: michael@0: /* Call GetAdaptersAddresses() twice. First, just to get the buf length */ michael@0: michael@0: buflen = 0; michael@0: michael@0: r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen); michael@0: if (r != ERROR_BUFFER_OVERFLOW) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen); michael@0: if (AdapterAddresses == NULL) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()"); michael@0: ABORT(R_NO_MEMORY); michael@0: } michael@0: michael@0: /* for real, this time */ michael@0: michael@0: r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen); michael@0: if (r != NO_ERROR) { michael@0: r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: /* Loop through the adapters */ michael@0: michael@0: for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) { michael@0: char *c; michael@0: michael@0: if (tmpAddress->OperStatus != IfOperStatusUp) michael@0: continue; michael@0: michael@0: snprintf(munged_ifname, IFNAMSIZ, "%S%c", tmpAddress->FriendlyName, 0); michael@0: /* replace spaces with underscores */ michael@0: c = strchr(munged_ifname, ' '); michael@0: while (c != NULL) { michael@0: *c = '_'; michael@0: c = strchr(munged_ifname, ' '); michael@0: } michael@0: c = strchr(munged_ifname, '.'); michael@0: while (c != NULL) { michael@0: *c = '+'; michael@0: c = strchr(munged_ifname, '+'); michael@0: } michael@0: michael@0: if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) { michael@0: IP_ADAPTER_UNICAST_ADDRESS *u = 0; michael@0: michael@0: for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) { michael@0: SOCKET_ADDRESS *sa_addr = &u->Address; michael@0: michael@0: if ((sa_addr->lpSockaddr->sa_family == AF_INET) || michael@0: (sa_addr->lpSockaddr->sa_family == AF_INET6)) { michael@0: if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr)))) michael@0: ABORT(r); michael@0: } michael@0: else { michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname); michael@0: continue; michael@0: } michael@0: michael@0: strlcpy(addrs[n].addr.ifname, munged_ifname, sizeof(addrs[n].addr.ifname)); michael@0: /* TODO: (Bug 895793) Getting interface properties for Windows */ michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN; michael@0: addrs[n].interface.estimated_speed = 0; michael@0: if (++n >= maxaddrs) michael@0: goto done; michael@0: } michael@0: } michael@0: } michael@0: michael@0: done: michael@0: *count = n; michael@0: _status = 0; michael@0: michael@0: abort: michael@0: RFREE(AdapterAddresses); michael@0: return _status; michael@0: } michael@0: #endif /* GET_WIN32_ADDRS_NO_WIN2K */ michael@0: michael@0: #elif defined(__sparc__) michael@0: michael@0: static int michael@0: stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: *count = 0; michael@0: UNIMPLEMENTED; /*TODO !nn! - sparc */ michael@0: return 0; michael@0: } michael@0: michael@0: #else michael@0: michael@0: static int michael@0: stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: struct ifconf ifc; michael@0: int _status; michael@0: int s = socket( AF_INET, SOCK_DGRAM, 0 ); michael@0: int len = 100 * sizeof(struct ifreq); michael@0: int r; michael@0: int e; michael@0: char *ptr; michael@0: int tl; michael@0: int n; michael@0: struct ifreq ifr2; michael@0: michael@0: char buf[ len ]; michael@0: michael@0: ifc.ifc_len = len; michael@0: ifc.ifc_buf = buf; michael@0: michael@0: e = ioctl(s,SIOCGIFCONF,&ifc); michael@0: ptr = buf; michael@0: tl = ifc.ifc_len; michael@0: n=0; michael@0: michael@0: while ( (tl > 0) && ( n < maxaddrs) ) michael@0: { michael@0: struct ifreq* ifr = (struct ifreq *)ptr; michael@0: michael@0: #ifdef LINUX michael@0: int si = sizeof(struct ifreq); michael@0: #ifndef ANDROID michael@0: struct ethtool_cmd ecmd; michael@0: struct iwreq wrq; michael@0: #endif michael@0: #else michael@0: int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)); michael@0: #endif michael@0: tl -= si; michael@0: ptr += si; michael@0: michael@0: ifr2 = *ifr; michael@0: michael@0: e = ioctl(s,SIOCGIFADDR,&ifr2); michael@0: if ( e == -1 ) michael@0: { michael@0: continue; michael@0: } michael@0: michael@0: //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e); michael@0: michael@0: if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address"); michael@0: } michael@0: else { michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN; michael@0: addrs[n].interface.estimated_speed = 0; michael@0: #if defined(LINUX) && !defined(ANDROID) michael@0: /* TODO (Bug 896851): interface property for Android */ michael@0: /* Getting ethtool for ethernet information. */ michael@0: ecmd.cmd = ETHTOOL_GSET; michael@0: ifr2.ifr_data = (void*)&ecmd; michael@0: e = ioctl(s, SIOCETHTOOL, &ifr2); michael@0: if (e == 0) michael@0: { michael@0: /* For wireless network, we won't get ethtool, it's a wired michael@0: connection */ michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED; michael@0: #ifdef DONT_HAVE_ETHTOOL_SPEED_HI michael@0: addrs[n].interface.estimated_speed = ecmd.speed; michael@0: #else michael@0: addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000; michael@0: #endif michael@0: } michael@0: michael@0: strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name)); michael@0: e = ioctl(s, SIOCGIWRATE, &wrq); michael@0: if (e == 0) michael@0: { michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI; michael@0: addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000; michael@0: } michael@0: michael@0: ifr2 = *ifr; michael@0: e = ioctl(s, SIOCGIFFLAGS, &ifr2); michael@0: if (e == 0) michael@0: { michael@0: if (ifr2.ifr_flags & IFF_POINTOPOINT) michael@0: { michael@0: addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN; michael@0: /* TODO (Bug 896913): find backend network type of this VPN */ michael@0: } michael@0: } michael@0: #endif michael@0: strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname)); michael@0: ++n; michael@0: } michael@0: } michael@0: michael@0: close(s); michael@0: michael@0: *count = n; michael@0: michael@0: _status = 0; michael@0: return _status; michael@0: } michael@0: #endif michael@0: michael@0: static int michael@0: nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr) michael@0: { michael@0: int i; michael@0: int different; michael@0: michael@0: for (i = 0; i < count; ++i) { michael@0: different = nr_transport_addr_cmp(&addrs[i].addr, &(addr->addr), michael@0: NR_TRANSPORT_ADDR_CMP_MODE_ALL); michael@0: if (!different) michael@0: return 1; /* duplicate */ michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int michael@0: nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count) michael@0: { michael@0: int r, _status; michael@0: nr_local_addr *tmp = 0; michael@0: int i; michael@0: int n; michael@0: michael@0: tmp = RMALLOC(*count * sizeof(*tmp)); michael@0: if (!tmp) michael@0: ABORT(R_NO_MEMORY); michael@0: michael@0: n = 0; michael@0: for (i = 0; i < *count; ++i) { michael@0: if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) { michael@0: /* skip addrs[i], it's a duplicate */ michael@0: } michael@0: else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) { michael@0: /* skip addrs[i], it's a loopback */ michael@0: } michael@0: else { michael@0: /* otherwise, copy it to the temporary array */ michael@0: if ((r=nr_local_addr_copy(&tmp[n], &addrs[i]))) michael@0: ABORT(r); michael@0: ++n; michael@0: } michael@0: } michael@0: michael@0: *count = n; michael@0: michael@0: /* copy temporary array into passed in/out array */ michael@0: for (i = 0; i < *count; ++i) { michael@0: if ((r=nr_local_addr_copy(&addrs[i], &tmp[i]))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: _status = 0; michael@0: abort: michael@0: RFREE(tmp); michael@0: return _status; michael@0: } michael@0: michael@0: #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS michael@0: michael@0: int michael@0: nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count) michael@0: { michael@0: int _status=0; michael@0: int i; michael@0: char typestr[100]; michael@0: michael@0: #if defined(BSD) || defined(DARWIN) michael@0: _status = stun_get_mib_addrs(addrs, maxaddrs, count); michael@0: #elif defined(WIN32) michael@0: _status = stun_get_win32_addrs(addrs, maxaddrs, count); michael@0: #elif defined(__sparc__) michael@0: _status = stun_get_sparc_addrs(addrs, maxaddrs, count); michael@0: #else michael@0: _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count); michael@0: #endif michael@0: michael@0: nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count); michael@0: michael@0: for (i = 0; i < *count; ++i) { michael@0: nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr)); michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n", michael@0: i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr); michael@0: } michael@0: michael@0: return _status; michael@0: } michael@0: michael@0: #endif