diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index e778bd48c8..90619085c4 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -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) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 351f2375df..a2b49f0b1e 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -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) || diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index 4e079864ec..cccea54f02 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -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)) { diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index cab2292389..9df93f109a 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -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