From 9a7f686ce7f6dc5298cef8a6e665bee673b6139d Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Sat, 6 Jun 2020 19:23:34 +0200 Subject: 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... --- common/socket.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'common') 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); } -- cgit v1.1-32-gdbae