diff options
Diffstat (limited to 'src/resolve/resolved-dns-scope.c')
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 4085b01..4780bc2 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; @@ -594,6 +596,7 @@ DnsScopeMatch dns_scope_good_domain( /* This returns the following return values: * * DNS_SCOPE_NO → This scope is not suitable for lookups of this domain, at all + * DNS_SCOPE_LAST_RESORT→ This scope is not suitable, unless we have no alternative * DNS_SCOPE_MAYBE → This scope is suitable, but only if nothing else wants it * DNS_SCOPE_YES_BASE+n → This scope is suitable, and 'n' suffix labels match * @@ -739,7 +742,7 @@ DnsScopeMatch dns_scope_good_domain( if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0)) - return DNS_SCOPE_MAYBE; + return DNS_SCOPE_LAST_RESORT; if ((dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */ dns_name_equal(domain, "local") == 0 && /* but not the single-label "local" name itself */ @@ -762,7 +765,7 @@ DnsScopeMatch dns_scope_good_domain( if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0)) - return DNS_SCOPE_MAYBE; + return DNS_SCOPE_LAST_RESORT; if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */ !is_gateway_hostname(domain) && /* don't resolve "_gateway" with LLMNR, let local synthesizing logic handle that */ @@ -1441,9 +1444,10 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) { continue; } - /* Collect service types for _services._dns-sd._udp.local RRs in a set */ + /* Collect service types for _services._dns-sd._udp.local RRs in a set. Only two-label names + * (not selective names) are considered according to RFC6763 § 9. */ if (!scope->announced && - dns_resource_key_is_dnssd_ptr(z->rr->key)) { + dns_resource_key_is_dnssd_two_label_ptr(z->rr->key)) { if (!set_contains(types, dns_resource_key_name(z->rr->key))) { r = set_ensure_put(&types, &dns_name_hash_ops, dns_resource_key_name(z->rr->key)); if (r < 0) |