|
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 /* 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> |
|
74 |
|
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 */ |
|
85 |
|
86 #include "stun.h" |
|
87 #include "addrs.h" |
|
88 |
|
89 |
|
90 |
|
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 */ |
|
123 |
|
124 #include <err.h> |
|
125 |
|
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); |
|
132 |
|
133 |
|
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)) |
|
141 |
|
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; |
|
149 |
|
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 } |
|
158 |
|
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; |
|
167 |
|
168 ifr.ifr_addr.sa_family = AF_INET; |
|
169 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); |
|
170 |
|
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 } |
|
175 |
|
176 while (addrcount > 0) { |
|
177 info.rti_addrs = ifam->ifam_addrs; |
|
178 |
|
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 */ |
|
184 |
|
185 switch (info.rti_info[RTAX_IFA]->sa_family) { |
|
186 case AF_INET: |
|
187 sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; |
|
188 |
|
189 if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr)))) |
|
190 ABORT(r); |
|
191 |
|
192 strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname)); |
|
193 |
|
194 ++*count; |
|
195 break; |
|
196 case AF_INET6: |
|
197 UNIMPLEMENTED; |
|
198 break; |
|
199 } |
|
200 |
|
201 addrcount--; |
|
202 |
|
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 } |
|
207 |
|
208 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); |
|
209 } |
|
210 |
|
211 _status = 0; |
|
212 abort: |
|
213 if (s != -1) close(s); |
|
214 return _status; |
|
215 } |
|
216 |
|
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]; |
|
232 |
|
233 *count = 0; |
|
234 |
|
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; |
|
241 |
|
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; |
|
249 |
|
250 next = buf; |
|
251 while (next < lim) { |
|
252 ifm = (struct if_msghdr *)next; |
|
253 |
|
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 } |
|
262 |
|
263 next += ifm->ifm_msglen; |
|
264 ifam = NULL; |
|
265 addrcount = 0; |
|
266 while (next < lim) { |
|
267 |
|
268 nextifm = (struct if_msghdr *)next; |
|
269 |
|
270 if (nextifm->ifm_type != RTM_NEWADDR) |
|
271 break; |
|
272 |
|
273 if (ifam == NULL) |
|
274 ifam = (struct ifa_msghdr *)nextifm; |
|
275 |
|
276 addrcount++; |
|
277 next += nextifm->ifm_msglen; |
|
278 } |
|
279 |
|
280 if (sdl->sdl_nlen > sizeof(name) - 1) { |
|
281 ABORT(R_INTERNAL); |
|
282 } |
|
283 |
|
284 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); |
|
285 name[sdl->sdl_nlen] = '\0'; |
|
286 |
|
287 stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count); |
|
288 } |
|
289 |
|
290 _status = 0; |
|
291 abort: |
|
292 if (buf) free(buf); |
|
293 return _status; |
|
294 } |
|
295 |
|
296 #elif defined(WIN32) |
|
297 |
|
298 #define WIN32_MAX_NUM_INTERFACES 20 |
|
299 |
|
300 |
|
301 #define _NR_MAX_KEY_LENGTH 256 |
|
302 #define _NR_MAX_NAME_LENGTH 512 |
|
303 |
|
304 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" |
|
305 |
|
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; |
|
316 |
|
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 |
|
323 |
|
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")); |
|
328 |
|
329 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg); |
|
330 |
|
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 } |
|
335 |
|
336 keyval_len = sizeof(keyval_buf); |
|
337 r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type, |
|
338 (BYTE *)keyval_buf, &keyval_len); |
|
339 |
|
340 RegCloseKey(adapter_reg); |
|
341 |
|
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 |
|
352 |
|
353 *friendly_name = my_fn; |
|
354 _status=0; |
|
355 |
|
356 abort: |
|
357 if (_status) { |
|
358 if (my_fn) free(my_fn); |
|
359 } |
|
360 return(_status); |
|
361 } |
|
362 |
|
363 |
|
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; |
|
375 |
|
376 *count = 0; |
|
377 |
|
378 pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO)); |
|
379 out_buf_len = sizeof(IP_ADAPTER_INFO); |
|
380 |
|
381 /* First call to GetAdaptersInfo is mainly to get length */ |
|
382 |
|
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"); |
|
396 |
|
397 pAdapter = pAdapterInfo; |
|
398 |
|
399 while (pAdapter) { |
|
400 char *c; |
|
401 |
|
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); |
|
404 |
|
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 } |
|
431 |
|
432 r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname); |
|
433 |
|
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); |
|
437 |
|
438 if (this_addr == 0) |
|
439 continue; |
|
440 |
|
441 r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String); |
|
442 |
|
443 addr->ip_version=NR_IPV4; |
|
444 addr->protocol = IPPROTO_UDP; |
|
445 |
|
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); |
|
451 |
|
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)); |
|
456 |
|
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; |
|
460 |
|
461 if (++n >= maxaddrs) |
|
462 goto done; |
|
463 } |
|
464 |
|
465 pAdapter = pAdapter->Next; |
|
466 } |
|
467 |
|
468 done: |
|
469 *count = n; |
|
470 _status = 0; |
|
471 |
|
472 abort: |
|
473 RFREE(pAdapterInfo); |
|
474 RFREE(friendly_name); |
|
475 return _status; |
|
476 } |
|
477 |
|
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; |
|
490 |
|
491 *count = 0; |
|
492 |
|
493 if (maxaddrs <= 0) |
|
494 ABORT(R_INTERNAL); |
|
495 |
|
496 /* Call GetAdaptersAddresses() twice. First, just to get the buf length */ |
|
497 |
|
498 buflen = 0; |
|
499 |
|
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 } |
|
505 |
|
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 } |
|
511 |
|
512 /* for real, this time */ |
|
513 |
|
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 } |
|
519 |
|
520 /* Loop through the adapters */ |
|
521 |
|
522 for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) { |
|
523 char *c; |
|
524 |
|
525 if (tmpAddress->OperStatus != IfOperStatusUp) |
|
526 continue; |
|
527 |
|
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 } |
|
540 |
|
541 if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) { |
|
542 IP_ADAPTER_UNICAST_ADDRESS *u = 0; |
|
543 |
|
544 for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) { |
|
545 SOCKET_ADDRESS *sa_addr = &u->Address; |
|
546 |
|
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 } |
|
556 |
|
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 } |
|
566 |
|
567 done: |
|
568 *count = n; |
|
569 _status = 0; |
|
570 |
|
571 abort: |
|
572 RFREE(AdapterAddresses); |
|
573 return _status; |
|
574 } |
|
575 #endif /* GET_WIN32_ADDRS_NO_WIN2K */ |
|
576 |
|
577 #elif defined(__sparc__) |
|
578 |
|
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 } |
|
586 |
|
587 #else |
|
588 |
|
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; |
|
602 |
|
603 char buf[ len ]; |
|
604 |
|
605 ifc.ifc_len = len; |
|
606 ifc.ifc_buf = buf; |
|
607 |
|
608 e = ioctl(s,SIOCGIFCONF,&ifc); |
|
609 ptr = buf; |
|
610 tl = ifc.ifc_len; |
|
611 n=0; |
|
612 |
|
613 while ( (tl > 0) && ( n < maxaddrs) ) |
|
614 { |
|
615 struct ifreq* ifr = (struct ifreq *)ptr; |
|
616 |
|
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; |
|
628 |
|
629 ifr2 = *ifr; |
|
630 |
|
631 e = ioctl(s,SIOCGIFADDR,&ifr2); |
|
632 if ( e == -1 ) |
|
633 { |
|
634 continue; |
|
635 } |
|
636 |
|
637 //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e); |
|
638 |
|
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 } |
|
662 |
|
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 } |
|
670 |
|
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 } |
|
686 |
|
687 close(s); |
|
688 |
|
689 *count = n; |
|
690 |
|
691 _status = 0; |
|
692 return _status; |
|
693 } |
|
694 #endif |
|
695 |
|
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; |
|
701 |
|
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 } |
|
708 |
|
709 return 0; |
|
710 } |
|
711 |
|
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; |
|
719 |
|
720 tmp = RMALLOC(*count * sizeof(*tmp)); |
|
721 if (!tmp) |
|
722 ABORT(R_NO_MEMORY); |
|
723 |
|
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 } |
|
739 |
|
740 *count = n; |
|
741 |
|
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 } |
|
747 |
|
748 _status = 0; |
|
749 abort: |
|
750 RFREE(tmp); |
|
751 return _status; |
|
752 } |
|
753 |
|
754 #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS |
|
755 |
|
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]; |
|
762 |
|
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 |
|
772 |
|
773 nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count); |
|
774 |
|
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 } |
|
780 |
|
781 return _status; |
|
782 } |
|
783 |
|
784 #endif |