Line data Source code
1 : /*
2 : Copyright (c) 2007, Adobe Systems, Incorporated
3 : All rights reserved.
4 :
5 : Redistribution and use in source and binary forms, with or without
6 : modification, are permitted provided that the following conditions are
7 : met:
8 :
9 : * Redistributions of source code must retain the above copyright
10 : notice, this list of conditions and the following disclaimer.
11 :
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.
15 :
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.
19 :
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 : */
32 :
33 :
34 : static char *RCSSTRING __UNUSED__="$Id: addrs.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
35 :
36 : #include <csi_platform.h>
37 : #include <assert.h>
38 : #include <string.h>
39 :
40 : #ifdef WIN32
41 : #include <winsock2.h>
42 : #include <iphlpapi.h>
43 : #include <tchar.h>
44 : #else /* !WIN32 */
45 :
46 : #include <sys/socket.h>
47 : #include <sys/ioctl.h>
48 : #include <errno.h>
49 :
50 : #ifndef ANDROID
51 : /* This works on linux and BSD, but not android */
52 : #include <sys/types.h> /* getifaddrs */
53 : #include <ifaddrs.h> /* getifaddrs */
54 : #else
55 : #include "ifaddrs-android.h"
56 : #define getifaddrs android_getifaddrs
57 : #define freeifaddrs android_freeifaddrs
58 : #endif
59 :
60 : #ifdef LINUX
61 :
62 : #ifdef ANDROID
63 : /* Work around an Android NDK < r8c bug */
64 : #undef __unused
65 : #else
66 : #include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
67 : #include <linux/wireless.h> /* struct iwreq */
68 : #include <linux/ethtool.h> /* struct ethtool_cmd */
69 : #include <linux/sockios.h> /* SIOCETHTOOL */
70 : #endif /* ANDROID */
71 :
72 : #endif /* LINUX */
73 :
74 : #endif /* !WIN32 */
75 :
76 : #include "stun.h"
77 : #include "addrs.h"
78 : #include "nr_crypto.h"
79 : #include "util.h"
80 :
81 : #if defined(WIN32)
82 :
83 : #define WIN32_MAX_NUM_INTERFACES 20
84 :
85 : #define NR_MD5_HASH_LENGTH 16
86 :
87 : #define _NR_MAX_KEY_LENGTH 256
88 : #define _NR_MAX_NAME_LENGTH 512
89 :
90 : #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
91 :
92 : static int nr_win32_get_adapter_friendly_name(char *adapter_GUID, char **friendly_name)
93 : {
94 : int r,_status;
95 : HKEY adapter_reg;
96 : TCHAR adapter_key[_NR_MAX_KEY_LENGTH];
97 : TCHAR keyval_buf[_NR_MAX_KEY_LENGTH];
98 : TCHAR adapter_GUID_tchar[_NR_MAX_NAME_LENGTH];
99 : DWORD keyval_len, key_type;
100 : size_t converted_chars, newlen;
101 : char *my_fn = 0;
102 :
103 : #ifdef _UNICODE
104 : mbstowcs_s(&converted_chars, adapter_GUID_tchar, strlen(adapter_GUID)+1,
105 : adapter_GUID, _TRUNCATE);
106 : #else
107 : strlcpy(adapter_GUID_tchar, adapter_GUID, _NR_MAX_NAME_LENGTH);
108 : #endif
109 :
110 : _tcscpy_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT(_ADAPTERS_BASE_REG));
111 : _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\"));
112 : _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, adapter_GUID_tchar);
113 : _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\Connection"));
114 :
115 : r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg);
116 :
117 : if (r != ERROR_SUCCESS) {
118 : r_log(NR_LOG_STUN, LOG_ERR, "Got error %d opening adapter reg key\n", r);
119 : ABORT(R_INTERNAL);
120 : }
121 :
122 : keyval_len = sizeof(keyval_buf);
123 : r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type,
124 : (BYTE *)keyval_buf, &keyval_len);
125 :
126 : RegCloseKey(adapter_reg);
127 :
128 : #ifdef UNICODE
129 : newlen = wcslen(keyval_buf)+1;
130 : my_fn = (char *) RCALLOC(newlen);
131 : if (!my_fn) {
132 : ABORT(R_NO_MEMORY);
133 : }
134 : wcstombs_s(&converted_chars, my_fn, newlen, keyval_buf, _TRUNCATE);
135 : #else
136 : my_fn = r_strdup(keyval_buf);
137 : #endif
138 :
139 : *friendly_name = my_fn;
140 : _status=0;
141 :
142 : abort:
143 : if (_status) {
144 : if (my_fn) free(my_fn);
145 : }
146 : return(_status);
147 : }
148 :
149 : static int
150 : stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
151 : {
152 : int r, _status;
153 : PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
154 : // recomended per https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
155 : static const ULONG initialBufLen = 15000;
156 : ULONG buflen = initialBufLen;
157 : char bin_hashed_ifname[NR_MD5_HASH_LENGTH];
158 : char hex_hashed_ifname[MAXIFNAME];
159 : int n = 0;
160 :
161 : *count = 0;
162 :
163 : if (maxaddrs <= 0)
164 : ABORT(R_BAD_ARGS);
165 :
166 : /* According to MSDN (see above) we have try GetAdapterAddresses() multiple times */
167 : for (n = 0; n < 5; n++) {
168 : AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
169 : if (AdapterAddresses == NULL) {
170 : r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
171 : ABORT(R_NO_MEMORY);
172 : }
173 :
174 : r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, AdapterAddresses, &buflen);
175 : if (r == NO_ERROR) {
176 : break;
177 : }
178 : r_log(NR_LOG_STUN, LOG_ERR, "GetAdaptersAddresses() returned error (%d)", r);
179 : RFREE(AdapterAddresses);
180 : AdapterAddresses = NULL;
181 : }
182 :
183 : if (n >= 5) {
184 : r_log(NR_LOG_STUN, LOG_ERR, "5 failures calling GetAdaptersAddresses()");
185 : ABORT(R_INTERNAL);
186 : }
187 :
188 : n = 0;
189 :
190 : /* Loop through the adapters */
191 :
192 : for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
193 :
194 : if (tmpAddress->OperStatus != IfOperStatusUp)
195 : continue;
196 :
197 : if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
198 : IP_ADAPTER_UNICAST_ADDRESS *u = 0;
199 :
200 : if(r=nr_crypto_md5((UCHAR *)tmpAddress->FriendlyName,
201 : wcslen(tmpAddress->FriendlyName) * sizeof(wchar_t),
202 : bin_hashed_ifname))
203 : ABORT(r);
204 : if(r=nr_bin2hex(bin_hashed_ifname, sizeof(bin_hashed_ifname),
205 : hex_hashed_ifname))
206 : ABORT(r);
207 :
208 : for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
209 : SOCKET_ADDRESS *sa_addr = &u->Address;
210 :
211 : if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
212 : (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
213 : if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr))))
214 : ABORT(r);
215 : }
216 : else {
217 : r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for address on adapter %lu", tmpAddress->IfIndex);
218 : continue;
219 : }
220 :
221 : strlcpy(addrs[n].addr.ifname, hex_hashed_ifname, sizeof(addrs[n].addr.ifname));
222 : if (tmpAddress->IfType == IF_TYPE_ETHERNET_CSMACD) {
223 : addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
224 : } else if (tmpAddress->IfType == IF_TYPE_IEEE80211) {
225 : /* Note: this only works for >= Win Vista */
226 : addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
227 : } else {
228 : addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
229 : }
230 : #if (_WIN32_WINNT >= 0x0600)
231 : /* Note: only >= Vista provide link speed information */
232 : addrs[n].interface.estimated_speed = tmpAddress->TransmitLinkSpeed / 1000;
233 : #else
234 : addrs[n].interface.estimated_speed = 0;
235 : #endif
236 : if (++n >= maxaddrs)
237 : goto done;
238 : }
239 : }
240 : }
241 :
242 : done:
243 : *count = n;
244 : _status = 0;
245 :
246 : abort:
247 : RFREE(AdapterAddresses);
248 : return _status;
249 : }
250 :
251 : #else /* WIN32 */
252 :
253 : static int
254 : nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
255 :
256 : static int
257 0 : stun_getifaddrs(nr_local_addr addrs[], int maxaddrs, int *count)
258 : {
259 : int r,_status;
260 0 : struct ifaddrs* if_addrs_head=NULL;
261 : struct ifaddrs* if_addr;
262 :
263 0 : *count = 0;
264 :
265 0 : if (maxaddrs <= 0)
266 0 : ABORT(R_BAD_ARGS);
267 :
268 0 : if (getifaddrs(&if_addrs_head) == -1) {
269 0 : r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
270 0 : ABORT(R_INTERNAL);
271 : }
272 :
273 0 : if_addr = if_addrs_head;
274 :
275 0 : while (if_addr && *count < maxaddrs) {
276 : /* This can be null */
277 0 : if (if_addr->ifa_addr) {
278 0 : switch (if_addr->ifa_addr->sa_family) {
279 : case AF_INET:
280 : case AF_INET6:
281 0 : if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
282 0 : r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
283 : } else {
284 : #if defined(LINUX) && !defined(ANDROID)
285 : struct ethtool_cmd ecmd;
286 : struct ifreq ifr;
287 : struct iwreq wrq;
288 : int e;
289 0 : int s = socket(AF_INET, SOCK_DGRAM, 0);
290 :
291 0 : strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name));
292 : /* TODO (Bug 896851): interface property for Android */
293 : /* Getting ethtool for ethernet information. */
294 0 : ecmd.cmd = ETHTOOL_GSET;
295 : /* In/out param */
296 0 : ifr.ifr_data = (void*)&ecmd;
297 :
298 0 : e = ioctl(s, SIOCETHTOOL, &ifr);
299 0 : if (e == 0)
300 : {
301 : /* For wireless network, we won't get ethtool, it's a wired
302 : * connection */
303 0 : addrs[*count].interface.type = NR_INTERFACE_TYPE_WIRED;
304 : #ifdef DONT_HAVE_ETHTOOL_SPEED_HI
305 : addrs[*count].interface.estimated_speed = ecmd.speed;
306 : #else
307 0 : addrs[*count].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
308 : #endif
309 : }
310 :
311 0 : strncpy(wrq.ifr_name, if_addr->ifa_name, sizeof(wrq.ifr_name));
312 0 : e = ioctl(s, SIOCGIWRATE, &wrq);
313 0 : if (e == 0)
314 : {
315 0 : addrs[*count].interface.type = NR_INTERFACE_TYPE_WIFI;
316 0 : addrs[*count].interface.estimated_speed = wrq.u.bitrate.value / 1000;
317 : }
318 :
319 0 : close(s);
320 :
321 0 : if (if_addr->ifa_flags & IFF_POINTOPOINT)
322 : {
323 0 : addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
324 : /* TODO (Bug 896913): find backend network type of this VPN */
325 : }
326 : #else
327 : addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
328 : addrs[*count].interface.estimated_speed = 0;
329 : #endif
330 0 : strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
331 0 : ++(*count);
332 : }
333 0 : break;
334 : default:
335 : ;
336 : }
337 : }
338 :
339 0 : if_addr = if_addr->ifa_next;
340 : }
341 :
342 0 : _status=0;
343 : abort:
344 0 : if (if_addrs_head) {
345 0 : freeifaddrs(if_addrs_head);
346 : }
347 0 : return(_status);
348 : }
349 :
350 : #endif
351 :
352 : static int
353 0 : nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
354 : {
355 : int i;
356 : int different;
357 :
358 0 : for (i = 0; i < count; ++i) {
359 0 : different = nr_transport_addr_cmp(&addrs[i].addr, &(addr->addr),
360 : NR_TRANSPORT_ADDR_CMP_MODE_ALL);
361 0 : if (!different)
362 0 : return 1; /* duplicate */
363 : }
364 :
365 0 : return 0;
366 : }
367 :
368 : int
369 0 : nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
370 : {
371 : int r, _status;
372 0 : nr_local_addr *tmp = 0;
373 : int i;
374 : int n;
375 :
376 0 : tmp = RMALLOC(*count * sizeof(*tmp));
377 0 : if (!tmp)
378 0 : ABORT(R_NO_MEMORY);
379 :
380 0 : n = 0;
381 0 : for (i = 0; i < *count; ++i) {
382 0 : if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
383 : /* skip addrs[i], it's a duplicate */
384 : }
385 0 : else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
386 : /* skip addrs[i], it's a loopback */
387 : }
388 0 : else if (remove_link_local &&
389 0 : addrs[i].addr.ip_version == NR_IPV6 &&
390 0 : nr_transport_addr_is_link_local(&addrs[i].addr)) {
391 : /* skip addrs[i], it's a link-local address */
392 : }
393 : else {
394 : /* otherwise, copy it to the temporary array */
395 0 : if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
396 0 : ABORT(r);
397 0 : ++n;
398 : }
399 : }
400 :
401 0 : *count = n;
402 :
403 0 : memset(addrs, 0, *count * sizeof(*addrs));
404 : /* copy temporary array into passed in/out array */
405 0 : for (i = 0; i < *count; ++i) {
406 0 : if ((r=nr_local_addr_copy(&addrs[i], &tmp[i])))
407 0 : ABORT(r);
408 : }
409 :
410 0 : _status = 0;
411 : abort:
412 0 : RFREE(tmp);
413 0 : return _status;
414 : }
415 :
416 : #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
417 :
418 : int
419 0 : nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
420 : {
421 0 : int _status=0;
422 : int i;
423 : char typestr[100];
424 :
425 : #ifdef WIN32
426 : _status = stun_get_win32_addrs(addrs, maxaddrs, count);
427 : #else
428 0 : _status = stun_getifaddrs(addrs, maxaddrs, count);
429 : #endif
430 :
431 0 : for (i = 0; i < *count; ++i) {
432 0 : nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
433 0 : r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
434 0 : i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
435 : }
436 :
437 0 : return _status;
438 : }
439 :
440 : #endif
|