mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
resolved: don't cache NXDOMAIN for SUDN resolver.arpa
The name resolver.arpa is reserved for RFC9462 "Discovery of Designated Resolvers" (DDR). This relies on regular dns queries for SVCB records at the special use domain name _dns.resolver.arpa. Unfortunately, older nameservers (or broken ones) won't know about this SUDN and will likely return NXDOMAIN. If this is cached, the cache entry will become an impediment for any clients trying to discover designated resolvers through the stub-resolver, or potentially even sd-resolved itself, were it to implement DDR. The RFC recommendation is that "clients MUST NOT perform A or AAAA queries for resolver.arpa", and "resolvers SHOULD respond to queries of any type other than SVCB for _dns.resolver.arpa. with NODATA and queries of any type for any domain name under resolver.arpa with NODATA." which should help avoid potential compatibility issues. This enforces that condition within sd-resolved, and avoids caching any such erroneous NXDOMAIN. The RFC also recommends requests for this domain should never be forwarded, to prevent authentication failures. Since there isn't much point in establishing secure communication to the local stub, we still allow SVCB to be forwarded from the stub, in case the client cares to implement some other authentication method and understands the consequences of skipping the local stub. Normal clients are not expected to implement DDR, but this change will protect sd-resolved's own caches in case they try. Although A and AAAA are prohibited, I think validating resolvers might reasonably query for dnssec records, even though the resolver.arpa zone does not exist (it is declared to be a locally served zone). For this reason, I have also added resolver.arpa to the builtin dnssec NTA.
This commit is contained in:
parent
bda7e4d2e5
commit
abcc94b351
@ -547,6 +547,20 @@ static int dns_cache_put_positive(
|
||||
TAKE_PTR(i);
|
||||
return 0;
|
||||
}
|
||||
/* https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml */
|
||||
/* https://www.iana.org/assignments/locally-served-dns-zones/locally-served-dns-zones.xhtml#transport-independent */
|
||||
static bool dns_special_use_domain_invalid_answer(DnsResourceKey *key, int rcode) {
|
||||
/* Sometimes we know a domain exists, even if broken nameservers say otherwise. Make sure not to
|
||||
* cache any answers we know are wrong. */
|
||||
|
||||
/* RFC9462 § 6.4: resolvers SHOULD respond to queries of any type other than SVCB for
|
||||
* _dns.resolver.arpa. with NODATA and queries of any type for any domain name under resolver.arpa
|
||||
* with NODATA. */
|
||||
if (dns_name_endswith(dns_resource_key_name(key), "resolver.arpa") > 0 && rcode == DNS_RCODE_NXDOMAIN)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int dns_cache_put_negative(
|
||||
DnsCache *c,
|
||||
@ -577,6 +591,8 @@ static int dns_cache_put_negative(
|
||||
return 0;
|
||||
if (dns_type_is_pseudo(key->type))
|
||||
return 0;
|
||||
if (dns_special_use_domain_invalid_answer(key, rcode))
|
||||
return 0;
|
||||
|
||||
if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) {
|
||||
if (!soa)
|
||||
|
@ -595,6 +595,29 @@ static DnsScopeMatch match_subnet_reverse_lookups(
|
||||
return _DNS_SCOPE_MATCH_INVALID;
|
||||
}
|
||||
|
||||
/* https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml */
|
||||
/* https://www.iana.org/assignments/locally-served-dns-zones/locally-served-dns-zones.xhtml */
|
||||
static bool dns_refuse_special_use_domain(const char *domain, DnsQuestion *question) {
|
||||
/* RFC9462 § 6.4: resolvers SHOULD respond to queries of any type other than SVCB for
|
||||
* _dns.resolver.arpa. with NODATA and queries of any type for any domain name under
|
||||
* resolver.arpa with NODATA. */
|
||||
if (dns_name_equal(domain, "_dns.resolver.arpa") > 0) {
|
||||
DnsResourceKey *t;
|
||||
|
||||
/* Only SVCB is permitted to _dns.resolver.arpa */
|
||||
DNS_QUESTION_FOREACH(t, question)
|
||||
if (t->type == DNS_TYPE_SVCB)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dns_name_endswith(domain, "resolver.arpa") > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DnsScopeMatch dns_scope_good_domain(
|
||||
DnsScope *s,
|
||||
DnsQuery *q,
|
||||
@ -651,6 +674,10 @@ DnsScopeMatch dns_scope_good_domain(
|
||||
if (dns_name_dont_resolve(domain))
|
||||
return DNS_SCOPE_NO;
|
||||
|
||||
/* Avoid asking invalid questions of some special use domains */
|
||||
if (dns_refuse_special_use_domain(domain, question))
|
||||
return DNS_SCOPE_NO;
|
||||
|
||||
/* Never go to network for the _gateway, _outbound, _localdnsstub, _localdnsproxy domain — they're something special, synthesized locally. */
|
||||
if (is_gateway_hostname(domain) ||
|
||||
is_outbound_hostname(domain) ||
|
||||
|
@ -477,7 +477,7 @@ int dns_synthesize_answer(
|
||||
|
||||
name = dns_resource_key_name(key);
|
||||
|
||||
if (dns_name_is_root(name)) {
|
||||
if (dns_name_is_root(name) || dns_name_endswith(name, "resolver.arpa") > 0) {
|
||||
/* Do nothing. */
|
||||
|
||||
} else if (dns_name_dont_resolve(name)) {
|
||||
|
@ -165,6 +165,11 @@ static int dns_trust_anchor_add_builtin_negative(DnsTrustAnchor *d) {
|
||||
/* Defined by RFC 8375. The most official choice. */
|
||||
"home.arpa\0"
|
||||
|
||||
/* RFC 9462 doesn't mention DNSSEC, but this domain
|
||||
* can't really be signed and clients need to validate
|
||||
* the answer before using it anyway. */
|
||||
"resolver.arpa\0"
|
||||
|
||||
/* RFC 8880 says because the 'ipv4only.arpa' zone has to
|
||||
* be an insecure delegation, DNSSEC cannot be used to
|
||||
* protect these answers from tampering by malicious
|
||||
|
Loading…
x
Reference in New Issue
Block a user