]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: rework how we determine which scope to send a query to
authorLennart Poettering <lennart@poettering.net>
Mon, 3 Dec 2018 15:25:00 +0000 (16:25 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 21 Dec 2018 10:04:11 +0000 (11:04 +0100)
Fixes: #10830 #9825 #9472
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h

index 746ff1b8bec93bc254f0f889c2c015d86875763f..7a4f97754b1c23a68dd738bc13a7240eb1798715 100644 (file)
@@ -682,22 +682,15 @@ int dns_query_go(DnsQuery *q) {
                         continue;
 
                 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
-                if (match < 0)
-                        return match;
-
-                if (match == DNS_SCOPE_NO)
+                if (match < 0) {
+                        log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
                         continue;
+                }
 
-                found = match;
-
-                if (match == DNS_SCOPE_YES) {
+                if (match > found) { /* Does this match better? If so, remember how well it matched, and the first one
+                                      * that matches this well */
+                        found = match;
                         first = s;
-                        break;
-                } else {
-                        assert(match == DNS_SCOPE_MAYBE);
-
-                        if (!first)
-                                first = s;
                 }
         }
 
@@ -725,10 +718,12 @@ int dns_query_go(DnsQuery *q) {
                         continue;
 
                 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
-                if (match < 0)
-                        goto fail;
+                if (match < 0) {
+                        log_debug("Couldn't check if '%s' matches agains scope, ignoring.", name);
+                        continue;
+                }
 
-                if (match != found)
+                if (match < found)
                         continue;
 
                 r = dns_query_add_candidate(q, s);
index 8ea46054a6de62d7084a11b239e5970a71df24b3..59f76b0ae9deeef9b0a709e3f875959674e562d5 100644 (file)
@@ -459,9 +459,25 @@ int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *add
         return dns_scope_socket(s, SOCK_STREAM, family, address, server, port, ret_socket_address);
 }
 
-DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
+DnsScopeMatch dns_scope_good_domain(
+                DnsScope *s,
+                int ifindex,
+                uint64_t flags,
+                const char *domain) {
+
         DnsSearchDomain *d;
 
+        /* This returns the following return values:
+         *
+         *    DNS_SCOPE_NO         → This scope is not suitable for lookups of this domain, at all
+         *    DNS_SCOPE_MAYBE      → This scope is suitable, but only if nothing else wants it
+         *    DNS_SCOPE_YES_BASE+n → This scope is suitable, and 'n' suffix labels match
+         *
+         *  (The idea is that the caller will only use the scopes with the longest 'n' returned. If no scopes return
+         *  DNS_SCOPE_YES_BASE+n, then it should use those which returned DNS_SCOPE_MAYBE. It should never use those
+         *  which returned DNS_SCOPE_NO.)
+         */
+
         assert(s);
         assert(domain);
 
@@ -497,6 +513,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
 
         case DNS_PROTOCOL_DNS: {
                 DnsServer *dns_server;
+                int n_best = -1;
 
                 /* Never route things to scopes that lack DNS servers */
                 dns_server = dns_scope_get_dns_server(s);
@@ -507,8 +524,22 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
                  * we return DNS_SCOPE_YES here, rather than just DNS_SCOPE_MAYBE, which means other wildcard scopes
                  * won't be considered anymore. */
                 LIST_FOREACH(domains, d, dns_scope_get_search_domains(s))
-                        if (dns_name_endswith(domain, d->name) > 0)
-                                return DNS_SCOPE_YES;
+                        if (dns_name_endswith(domain, d->name) > 0) {
+                                int c;
+
+                                c = dns_name_count_labels(d->name);
+                                if (c < 0)
+                                        continue;
+
+                                if (c > n_best)
+                                        n_best = c;
+                        }
+
+                /* Let's return the number of labels in the best matching result */
+                if (n_best >= 0) {
+                        assert(n_best <= DNS_SCOPE_YES_END - DNS_SCOPE_YES_BASE);
+                        return DNS_SCOPE_YES_BASE + n_best;
+                }
 
                 /* If the DNS server has route-only domains, don't send other requests to it. This would be a privacy
                  * violation, will most probably fail anyway, and adds unnecessary load. */
index 7b7236751ba3f7c614aaf1239cc2da60c8b10b88..546d01c65611ac93dd1103db8ef721db57b6dd2d 100644 (file)
@@ -18,7 +18,8 @@ typedef struct DnsScope DnsScope;
 typedef enum DnsScopeMatch {
         DNS_SCOPE_NO,
         DNS_SCOPE_MAYBE,
-        DNS_SCOPE_YES,
+        DNS_SCOPE_YES_BASE, /* Add the number of matching labels to this */
+        DNS_SCOPE_YES_END = DNS_SCOPE_YES_BASE + DNS_N_LABELS_MAX,
         _DNS_SCOPE_MATCH_MAX,
         _DNS_SCOPE_MATCH_INVALID = -1
 } DnsScopeMatch;