summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2020-06-06 19:23:34 +0200
committerGravatar Martin Szulecki2020-06-06 19:23:34 +0200
commit9a7f686ce7f6dc5298cef8a6e665bee673b6139d (patch)
treeca35f83f8448180463cdb915dc05ad8bb996fada /common
parent574d7f82b78f7b5703eaaff227a5075aa2afb1a5 (diff)
downloadlibimobiledevice-9a7f686ce7f6dc5298cef8a6e665bee673b6139d.tar.gz
libimobiledevice-9a7f686ce7f6dc5298cef8a6e665bee673b6139d.tar.bz2
socket: Improve IPv6 scope id detection to fix network devices on OSX
The helper should now also work for loopback addresses and prefer any initially supplied scope id to maintain routing information if possible. Otherwise it just picks the best suitable route. Let us see if this is stable enough to prevent us from adding routing table parsing cruft and other logic...
Diffstat (limited to 'common')
-rw-r--r--common/socket.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/common/socket.c b/common/socket.c
index 26cf496..749e0ef 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -344,15 +344,14 @@ static uint32_t _in6_addr_scope(struct in6_addr* addr)
344 return scope; 344 return scope;
345} 345}
346 346
347static int32_t _in6_addr_scope_id(struct in6_addr* addr) 347static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
348{ 348{
349 int32_t res = -1; 349 int32_t res = -1;
350
351 struct ifaddrs *ifaddr, *ifa; 350 struct ifaddrs *ifaddr, *ifa;
352 uint32_t addr_scope; 351 uint32_t addr_scope;
353 352
354 /* get scope for requested address */ 353 /* get scope for requested address */
355 addr_scope = _in6_addr_scope(addr); 354 addr_scope = _in6_addr_scope(&addr->sin6_addr);
356 if (addr_scope == 0) { 355 if (addr_scope == 0) {
357 /* global scope doesn't need a specific scope id */ 356 /* global scope doesn't need a specific scope id */
358 return addr_scope; 357 return addr_scope;
@@ -393,10 +392,29 @@ static int32_t _in6_addr_scope_id(struct in6_addr* addr)
393 continue; 392 continue;
394 } 393 }
395 394
396 /* use the scope id of this interface */ 395 /* use if address is equal */
396 if (memcmp(&addr->sin6_addr.s6_addr, &addr_in->sin6_addr.s6_addr, sizeof(addr_in->sin6_addr.s6_addr)) == 0) {
397 res = addr_in->sin6_scope_id;
398 /* if scope id equals the requested one then assume it was valid */
399 if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
400 break;
401 } else {
402 continue;
403 }
404 }
405
406 /* skip loopback interface if not already matched exactly above */
407 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
408 continue;
409 }
410
411 /* set the scope id of this interface as most likely candidate */
397 res = addr_in->sin6_scope_id; 412 res = addr_in->sin6_scope_id;
398 413
399 break; 414 /* if scope id equals the requested one then assume it was valid */
415 if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
416 break;
417 }
400 } 418 }
401 419
402 freeifaddrs(ifaddr); 420 freeifaddrs(ifaddr);
@@ -442,7 +460,7 @@ int socket_connect_addr(struct sockaddr* addr, uint16_t port)
442 * a scope id from a suitable interface on this system or routing might 460 * a scope id from a suitable interface on this system or routing might
443 * fail. An IPv6 guru should have another look though... 461 * fail. An IPv6 guru should have another look though...
444 */ 462 */
445 addr_in->sin6_scope_id = _in6_addr_scope_id(&addr_in->sin6_addr); 463 addr_in->sin6_scope_id = _sockaddr_in6_scope_id(addr_in);
446 464
447 addrlen = sizeof(struct sockaddr_in6); 465 addrlen = sizeof(struct sockaddr_in6);
448 } 466 }