From: Ronan Pigott Date: Fri, 1 Mar 2024 04:42:43 +0000 (-0700) Subject: resolve: skip IP_UNICAST_IF for local sockets X-Git-Tag: v256-rc1~674 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51d056858eadc3068633b32c78acf248e0974f26;p=thirdparty%2Fsystemd.git resolve: skip IP_UNICAST_IF for local sockets SO_BINDTODEVICE was used during connect() to fix an issue where IP_UNICAST_IF was improperly ignored for route lookups made by connect in linux. This has since been resolved upstream [1][2], but as a result we must apply the local socket excpetion to IP_UNICAST_IF as well. The SO_BINDTODEVICE is no longer necessary, but left in place for 5.x kernels. [1] https://lore.kernel.org/all/20220829111554.GA1771@debian/ [2] https://lore.kernel.org/all/20221208145437.GA75680@debian/ --- diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 40615ff6051..e390715807f 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -424,7 +424,15 @@ static int dns_scope_socket( return r; } - if (ifindex != 0) { + bool addr_is_nonlocal = s->link && + !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) && + in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0; + + if (addr_is_nonlocal && ifindex != 0) { + /* As a special exception we don't use UNICAST_IF if we notice that the specified IP address + * is on the local host. Otherwise, destination addresses on the local host result in + * EHOSTUNREACH, since Linux won't send the packets out of the specified interface, but + * delivers them directly to the local socket. */ r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex); if (r < 0) return r; @@ -463,19 +471,13 @@ static int dns_scope_socket( else { bool bound = false; - /* Let's temporarily bind the socket to the specified ifindex. The kernel currently takes - * only the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions + /* Let's temporarily bind the socket to the specified ifindex. Older kernels only take + * the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions * in connect() — and not IP_UNICAST_IF. We don't really want any of the other semantics of * SO_BINDTODEVICE/SO_BINDTOINDEX, hence we immediately unbind the socket after the fact * again. - * - * As a special exception we don't do this if we notice that the specified IP address is on - * the local host. SO_BINDTODEVICE in combination with destination addresses on the local - * host result in EHOSTUNREACH, since Linux won't send the packets out of the specified - * interface, but delivers them directly to the local socket. */ - if (s->link && - !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) && - in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0) { + */ + if (addr_is_nonlocal) { r = socket_bind_to_ifindex(fd, ifindex); if (r < 0) return r;