resolved: bind .local domains to mDNS with DNS_SCOPE_YES, similar LLMNR

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
This commit is contained in:
Lennart Poettering 2018-12-03 22:27:19 +01:00
parent a97a3b256c
commit 1750854916
2 changed files with 47 additions and 9 deletions

View File

@ -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");

View File

@ -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