]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: do DNS RR type based routing
authorLennart Poettering <lennart@poettering.net>
Tue, 5 Mar 2024 08:48:35 +0000 (09:48 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 Mar 2024 14:29:25 +0000 (15:29 +0100)
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
src/resolve/resolved-dns-scope.h

index 94c7674a8f5c72daa21043ce02ea1607c3064d07..0b5e907bcf919c6e1b2f65dc596d06247a9c39a4 100644 (file)
@@ -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;
+}
index e2eb023c1dff0599b279d6d5713924ca034bb725..4d39dc6f5d0639870898a7784489343585b3e8f6 100644 (file)
@@ -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);