From 1750854916df6a777e6c12451eb5eb2aebbc93fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 3 Dec 2018 22:27:19 +0100 Subject: resolved: bind .local domains to mDNS with DNS_SCOPE_YES, similar LLMNR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we'd return DNS_SCOPE_MAYBE for all domain lookups matching LLMNR or mDNS. Let's upgrade this to DNS_SCOPE_YES, to make the binding stronger. The effect of this is that even if "local" is defined as routing domain on some iface, we'll still lookup domains in local via mDNS — if mDNS is turned on. This should not be limiting, as people who don't want such lookups should turn off mDNS altogether, as it is useless if nothing is routed to it. This also has the nice benefit that mDNS/LLMR continue to work if people use "~." as routing domain on some interface. Similar for LLMNR and single label names. Similar also for the link local IPv4 and IPv6 reverse lookups. Fixes: #10125 --- src/resolve/resolved-dns-scope.c | 54 ++++++++++++++++++++++++++++++++++------ test/networkd-test.py | 2 +- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 59f76b0ae..c2e4d55a3 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -459,6 +459,21 @@ int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *add return dns_scope_socket(s, SOCK_STREAM, family, address, server, port, ret_socket_address); } +static DnsScopeMatch accept_link_local_reverse_lookups(const char *domain) { + assert(domain); + + if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0) + return DNS_SCOPE_YES_BASE + 4; /* 4 labels match */ + + if (dns_name_endswith(domain, "8.e.f.ip6.arpa") > 0 || + dns_name_endswith(domain, "9.e.f.ip6.arpa") > 0 || + dns_name_endswith(domain, "a.e.f.ip6.arpa") > 0 || + dns_name_endswith(domain, "b.e.f.ip6.arpa") > 0) + return DNS_SCOPE_YES_BASE + 5; /* 5 labels match */ + + return _DNS_SCOPE_MATCH_INVALID; +} + DnsScopeMatch dns_scope_good_domain( DnsScope *s, int ifindex, @@ -561,25 +576,48 @@ DnsScopeMatch dns_scope_good_domain( return DNS_SCOPE_NO; } - case DNS_PROTOCOL_MDNS: + case DNS_PROTOCOL_MDNS: { + DnsScopeMatch m; + + m = accept_link_local_reverse_lookups(domain); + if (m >= 0) + return m; + if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || - (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || - (dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */ + (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0)) + return DNS_SCOPE_MAYBE; + + 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 */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via mDNS */ - return DNS_SCOPE_MAYBE; + return DNS_SCOPE_YES_BASE + 1; /* Return +1, as the top-level .local domain matches, i.e. one label */ return DNS_SCOPE_NO; + } + + case DNS_PROTOCOL_LLMNR: { + DnsScopeMatch m; + + m = accept_link_local_reverse_lookups(domain); + if (m >= 0) + return m; - case DNS_PROTOCOL_LLMNR: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || - (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || - (dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */ + (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0)) + return DNS_SCOPE_MAYBE; + + 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 nss-myhostname handle this */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */ - return DNS_SCOPE_MAYBE; + return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative for + * single-label names, i.e. one label. This is particular + * relevant as it means a "." route on some other scope won't + * pull all traffic away from us. (If people actually want to + * pull traffic away from us they should turn off LLMNR on the + * link) */ return DNS_SCOPE_NO; + } default: assert_not_reached("Unknown scope protocol"); diff --git a/test/networkd-test.py b/test/networkd-test.py index 176d52a02..7011abc96 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -652,7 +652,7 @@ Domains= ~company ~lab''') conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf' os.makedirs(os.path.dirname(conf), exist_ok=True) with open(conf, 'w') as f: - f.write('[Resolve]\nDNSSEC=no') + f.write('[Resolve]\nDNSSEC=no\nLLMNR=no\nMulticastDNS=no\n') self.addCleanup(os.remove, conf) # create /etc/hosts bind mount which resolves my.example for IPv4 -- cgit v1.2.3-65-gdbad