addrs-win32.c (6257B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef WIN32 6 7 #include "addrs-win32.h" 8 #include <csi_platform.h> 9 #include <assert.h> 10 #include <string.h> 11 #include "util.h" 12 #include "stun_util.h" 13 #include "util.h" 14 #include <r_macros.h> 15 #include "nr_crypto.h" 16 17 #include <winsock2.h> 18 #include <iphlpapi.h> 19 #include <tchar.h> 20 21 #define WIN32_MAX_NUM_INTERFACES 20 22 23 #define NR_MD5_HASH_LENGTH 16 24 25 #define _NR_MAX_KEY_LENGTH 256 26 #define _NR_MAX_NAME_LENGTH 512 27 28 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" 29 30 static int nr_win32_get_adapter_friendly_name(char *adapter_GUID, char **friendly_name) 31 { 32 int r,_status; 33 HKEY adapter_reg; 34 TCHAR adapter_key[_NR_MAX_KEY_LENGTH]; 35 TCHAR keyval_buf[_NR_MAX_KEY_LENGTH]; 36 TCHAR adapter_GUID_tchar[_NR_MAX_NAME_LENGTH]; 37 DWORD keyval_len, key_type; 38 size_t converted_chars, newlen; 39 char *my_fn = 0; 40 41 #ifdef _UNICODE 42 mbstowcs_s(&converted_chars, adapter_GUID_tchar, strlen(adapter_GUID)+1, 43 adapter_GUID, _TRUNCATE); 44 #else 45 strlcpy(adapter_GUID_tchar, adapter_GUID, _NR_MAX_NAME_LENGTH); 46 #endif 47 48 _tcscpy_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT(_ADAPTERS_BASE_REG)); 49 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\")); 50 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, adapter_GUID_tchar); 51 _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\Connection")); 52 53 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg); 54 55 if (r != ERROR_SUCCESS) { 56 r_log(NR_LOG_STUN, LOG_ERR, "Got error %d opening adapter reg key\n", r); 57 ABORT(R_INTERNAL); 58 } 59 60 keyval_len = sizeof(keyval_buf); 61 r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type, 62 (BYTE *)keyval_buf, &keyval_len); 63 64 RegCloseKey(adapter_reg); 65 66 #ifdef UNICODE 67 newlen = wcslen(keyval_buf)+1; 68 my_fn = (char *) RCALLOC(newlen); 69 if (!my_fn) { 70 ABORT(R_NO_MEMORY); 71 } 72 wcstombs_s(&converted_chars, my_fn, newlen, keyval_buf, _TRUNCATE); 73 #else 74 my_fn = r_strdup(keyval_buf); 75 #endif 76 77 *friendly_name = my_fn; 78 _status=0; 79 80 abort: 81 if (_status) { 82 if (my_fn) free(my_fn); 83 } 84 return(_status); 85 } 86 87 static int stun_win32_address_disallowed(IP_ADAPTER_UNICAST_ADDRESS *addr) 88 { 89 return (addr->DadState != NldsPreferred) && 90 (addr->DadState != IpDadStatePreferred); 91 } 92 93 static int stun_win32_address_temp_v6(IP_ADAPTER_UNICAST_ADDRESS *addr) 94 { 95 return (addr->Address.lpSockaddr->sa_family == AF_INET6) && 96 (addr->SuffixOrigin == IpSuffixOriginRandom); 97 } 98 99 int 100 stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count) 101 { 102 int r, _status; 103 PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL; 104 // recomended per https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx 105 static const ULONG initialBufLen = 15000; 106 ULONG buflen = initialBufLen; 107 char bin_hashed_ifname[NR_MD5_HASH_LENGTH]; 108 char hex_hashed_ifname[MAXIFNAME]; 109 int n = 0; 110 111 *count = 0; 112 113 if (maxaddrs <= 0) 114 ABORT(R_BAD_ARGS); 115 116 /* According to MSDN (see above) we have try GetAdapterAddresses() multiple times */ 117 for (n = 0; n < 5; n++) { 118 AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen); 119 if (AdapterAddresses == NULL) { 120 r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()"); 121 ABORT(R_NO_MEMORY); 122 } 123 124 r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, AdapterAddresses, &buflen); 125 if (r == NO_ERROR) { 126 break; 127 } 128 r_log(NR_LOG_STUN, LOG_ERR, "GetAdaptersAddresses() returned error (%d)", r); 129 RFREE(AdapterAddresses); 130 AdapterAddresses = NULL; 131 } 132 133 if (n >= 5) { 134 r_log(NR_LOG_STUN, LOG_ERR, "5 failures calling GetAdaptersAddresses()"); 135 ABORT(R_INTERNAL); 136 } 137 138 n = 0; 139 140 /* Loop through the adapters */ 141 142 for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) { 143 144 if (tmpAddress->OperStatus != IfOperStatusUp) 145 continue; 146 147 if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) { 148 IP_ADAPTER_UNICAST_ADDRESS *u = 0; 149 150 if(r=nr_crypto_md5((UCHAR *)tmpAddress->FriendlyName, 151 wcslen(tmpAddress->FriendlyName) * sizeof(wchar_t), 152 bin_hashed_ifname)) 153 ABORT(r); 154 if(r=nr_bin2hex(bin_hashed_ifname, sizeof(bin_hashed_ifname), 155 hex_hashed_ifname)) 156 ABORT(r); 157 158 for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) { 159 SOCKET_ADDRESS *sa_addr = &u->Address; 160 161 if ((sa_addr->lpSockaddr->sa_family != AF_INET) && 162 (sa_addr->lpSockaddr->sa_family != AF_INET6)) { 163 r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for address on adapter %lu", tmpAddress->IfIndex); 164 continue; 165 } 166 167 if (stun_win32_address_disallowed(u)) { 168 continue; 169 } 170 171 if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr)))) { 172 ABORT(r); 173 } 174 175 strlcpy(addrs[n].addr.ifname, hex_hashed_ifname, sizeof(addrs[n].addr.ifname)); 176 if (tmpAddress->IfType == IF_TYPE_ETHERNET_CSMACD) { 177 addrs[n].iface.type = NR_INTERFACE_TYPE_WIRED; 178 } else if (tmpAddress->IfType == IF_TYPE_IEEE80211) { 179 /* Note: this only works for >= Win Vista */ 180 addrs[n].iface.type = NR_INTERFACE_TYPE_WIFI; 181 } else { 182 addrs[n].iface.type = NR_INTERFACE_TYPE_UNKNOWN; 183 } 184 addrs[n].iface.estimated_speed = tmpAddress->TransmitLinkSpeed / 1000; 185 if (stun_win32_address_temp_v6(u)) { 186 addrs[n].flags |= NR_ADDR_FLAG_TEMPORARY; 187 } 188 189 if (++n >= maxaddrs) 190 goto done; 191 } 192 } 193 } 194 195 done: 196 *count = n; 197 _status = 0; 198 199 abort: 200 RFREE(AdapterAddresses); 201 return _status; 202 } 203 204 #endif //WIN32