From 8841d1cef89116ba34738e58e8f035188fb68ecd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Mar 2024 09:48:35 +0100 Subject: [PATCH] resolved: do DNS RR type based routing So far we only looked at the domain name when routing requests to specific scopes. With this we'll also take the DNS RR type into account. This takes benefit of the fact that lookups for RRs such as SOA or NS or the various DNSSEC RR types never really make sense to be routed to LLMNR or mDNS, since they don't have concepts there. This hence refuses to route requests for those RR types to the LLMNR/mDNS scopes, which hence means they'll likely be routed to classic DNS instead. This should improve behaviour of tools that assumes it speaks to classic DNS only via 127.0.0.53, since it will now usually do that. --- src/resolve/resolved-dns-scope.c | 69 +++++++++++++++++++++++++++++++- src/resolve/resolved-dns-scope.h | 3 ++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 94c7674a8f5..0b5e907bcf9 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -599,7 +599,7 @@ DnsScopeMatch dns_scope_good_domain( DnsQuestion *question; const char *domain; uint64_t flags; - int ifindex; + int ifindex, r; /* This returns the following return values: * @@ -653,6 +653,11 @@ DnsScopeMatch dns_scope_good_domain( is_dns_proxy_stub_hostname(domain)) return DNS_SCOPE_NO; + /* Never send SOA or NS or DNSSEC request to LLMNR, where they make little sense. */ + r = dns_question_types_suitable_for_protocol(question, s->protocol); + if (r <= 0) + return DNS_SCOPE_NO; + switch (s->protocol) { case DNS_PROTOCOL_DNS: { @@ -1685,3 +1690,65 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) { JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)), JSON_BUILD_PAIR_VARIANT("cache", cache))); } + +int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol) { + + /* Tests whether it makes sense to route queries for the specified DNS RR types to the specified + * protocol. For classic DNS pretty much all RR types are suitable, but for LLMNR/mDNS let's + * allowlist only a few that make sense. We use this when routing queries so that we can more quickly + * return errors for queries that will almost certainly fail/time-out otherwise. For example, this + * ensures that SOA, NS, or DS/DNSKEY queries are never routed to mDNS/LLMNR where they simply make + * no sense. */ + + if (dns_type_is_obsolete(type)) + return false; + + if (!dns_type_is_valid_query(type)) + return false; + + switch (protocol) { + + case DNS_PROTOCOL_DNS: + return true; + + case DNS_PROTOCOL_LLMNR: + return IN_SET(type, + DNS_TYPE_ANY, + DNS_TYPE_A, + DNS_TYPE_AAAA, + DNS_TYPE_CNAME, + DNS_TYPE_PTR, + DNS_TYPE_TXT); + + case DNS_PROTOCOL_MDNS: + return IN_SET(type, + DNS_TYPE_ANY, + DNS_TYPE_A, + DNS_TYPE_AAAA, + DNS_TYPE_CNAME, + DNS_TYPE_PTR, + DNS_TYPE_TXT, + DNS_TYPE_SRV, + DNS_TYPE_NSEC, + DNS_TYPE_HINFO); + + default: + return -EPROTONOSUPPORT; + } +} + +int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol) { + DnsResourceKey *key; + int r; + + /* Tests whether the types in the specified question make any sense to be routed to the specified + * protocol, i.e. if dns_type_suitable_for_protocol() is true for any of the contained RR types */ + + DNS_QUESTION_FOREACH(key, q) { + r = dns_type_suitable_for_protocol(key->type, protocol); + if (r != 0) + return r; + } + + return false; +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index e2eb023c1df..4d39dc6f5d0 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -112,3 +112,6 @@ int dns_scope_remove_dnssd_services(DnsScope *scope); bool dns_scope_is_default_route(DnsScope *scope); int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret); + +int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol); +int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol); -- 2.47.3