diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 94c7674a8f..0b5e907bcf 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 e2eb023c1d..4d39dc6f5d 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);