summaryrefslogtreecommitdiffstats
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
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...
-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)
return scope;
}
-static int32_t _in6_addr_scope_id(struct in6_addr* addr)
+static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
{
int32_t res = -1;
-
struct ifaddrs *ifaddr, *ifa;
uint32_t addr_scope;
/* get scope for requested address */
- addr_scope = _in6_addr_scope(addr);
+ addr_scope = _in6_addr_scope(&addr->sin6_addr);
if (addr_scope == 0) {
/* global scope doesn't need a specific scope id */
return addr_scope;
@@ -393,10 +392,29 @@ static int32_t _in6_addr_scope_id(struct in6_addr* addr)
continue;
}
- /* use the scope id of this interface */
+ /* use if address is equal */
+ if (memcmp(&addr->sin6_addr.s6_addr, &addr_in->sin6_addr.s6_addr, sizeof(addr_in->sin6_addr.s6_addr)) == 0) {
+ res = addr_in->sin6_scope_id;
+ /* if scope id equals the requested one then assume it was valid */
+ if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ /* skip loopback interface if not already matched exactly above */
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+ continue;
+ }
+
+ /* set the scope id of this interface as most likely candidate */
res = addr_in->sin6_scope_id;
- break;
+ /* if scope id equals the requested one then assume it was valid */
+ if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
+ break;
+ }
}
freeifaddrs(ifaddr);
@@ -442,7 +460,7 @@ int socket_connect_addr(struct sockaddr* addr, uint16_t port)
* a scope id from a suitable interface on this system or routing might
* fail. An IPv6 guru should have another look though...
*/
- addr_in->sin6_scope_id = _in6_addr_scope_id(&addr_in->sin6_addr);
+ addr_in->sin6_scope_id = _sockaddr_in6_scope_id(addr_in);
addrlen = sizeof(struct sockaddr_in6);
}