]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Resolver is parent-centric
authorColin Vidal <colin@isc.org>
Mon, 30 Mar 2026 09:45:15 +0000 (11:45 +0200)
committerColin Vidal <colin@isc.org>
Mon, 30 Mar 2026 18:41:13 +0000 (20:41 +0200)
The resolver now uses glue addresses from `dns_deleg_t` objects stored
in the delegation database.  The main cache is still used for ADB A/AAAA
lookups when no glue is available for a nameserver name.

The resolver's `fctx_getaddresses()` is refactored to, for each
delegation of the delegation set, try to get the address-based finds,
then nameserver name lookups. (Later, the logic to handle DELEG
`include-delegparm=` will be hooked there too.)

lib/dns/adb.c
lib/dns/include/dns/adb.h
lib/dns/resolver.c

index 6c02ed86a46e194891346d0aea79eae724fedcc7..341f9c96cdacea86d1648d8fdd7a04d4dbb38103 100644 (file)
@@ -1716,23 +1716,29 @@ dns_adb_shutdown(dns_adb_t *adb) {
 
 static void
 findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *addr,
-            dns_adbaddrinfo_t **adbaddrp, isc_stdtime_t now) {
+            dns_adbaddrinfo_t **adbaddrp, isc_stdtime_t now,
+            unsigned int options) {
        dns_adbentry_t *adbentry = get_attached_and_locked_entry(adb, now,
                                                                 addr);
+       if ((options & DNS_ADBFIND_QUOTAEXEMPT) == 0 &&
+           adbentry_overquota(adbentry))
+       {
+               goto out;
+       }
 
        in_port_t port = isc_sockaddr_getport(addr);
        *adbaddrp = new_adbaddrinfo(adb, adbentry, port);
 
+out:
        UNLOCK(&adbentry->lock);
        dns_adbentry_detach(&adbentry);
 }
 
-isc_result_t
+void
 dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
                            in_port_t port, unsigned int options,
                            isc_stdtime_t now, size_t maxaddrs,
                            dns_adbfind_t **findp, size_t *findlen) {
-       isc_result_t result = ISC_R_SUCCESS;
        dns_adbfind_t *find = NULL;
        isc_sockaddr_t sockaddr = {};
 
@@ -1743,7 +1749,8 @@ dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
        rcu_read_lock();
 
        if (atomic_load(&adb->shuttingdown)) {
-               CLEANUP(ISC_R_SHUTTINGDOWN);
+               rcu_read_unlock();
+               return;
        }
 
        if (now == 0) {
@@ -1779,7 +1786,12 @@ dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
                        UNREACHABLE();
                }
 
-               findaddrinfo(adb, &sockaddr, &addrinfo, now);
+               findaddrinfo(adb, &sockaddr, &addrinfo, now, options);
+               if (addrinfo == NULL) {
+                       find->options |= DNS_ADBFIND_OVERQUOTA;
+                       continue;
+               }
+
                ISC_LIST_APPEND(find->list, addrinfo, publink);
                (*findlen)++;
 
@@ -1789,9 +1801,7 @@ dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
        }
 
        *findp = find;
-cleanup:
        rcu_read_unlock();
-       return result;
 }
 
 /*
@@ -3217,7 +3227,7 @@ dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *addr,
                return ISC_R_SHUTTINGDOWN;
        }
 
-       findaddrinfo(adb, addr, adbaddrp, now);
+       findaddrinfo(adb, addr, adbaddrp, now, DNS_ADBFIND_QUOTAEXEMPT);
 
        rcu_read_unlock();
 
index 157f8da0b2bfd50dc082f9a8bb15a8440e63b1a7..cce3970df55a3843ef8d8934380ab8eab94a633b 100644 (file)
@@ -346,7 +346,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg,
  *     returns.
  */
 
-isc_result_t
+void
 dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
                            in_port_t port, unsigned int options,
                            isc_stdtime_t now, size_t maxaddrs,
index fdba143019130d861cfcc5aa7cc7e4ba433bfb26..84da407be509514c5582ad835572ccb456ec17e8 100644 (file)
@@ -3654,47 +3654,123 @@ fctx_getaddresses_forwarders(fetchctx_t *fctx) {
        return DNS_R_CONTINUE;
 }
 
+static void
+fctx_getaddresses_addresses(fetchctx_t *fctx, isc_stdtime_t now,
+                           unsigned int options, bool *allspilledp,
+                           size_t *ns_processed) {
+       dns_adbfindlist_t finds = ISC_LIST_INITIALIZER;
+       size_t max_delegation_servers = fctx->res->view->max_delegation_servers;
+
+       if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) {
+               options |= DNS_ADBFIND_QUOTAEXEMPT;
+       }
+
+       ISC_LIST_FOREACH(fctx->delegset->delegs, deleg, link) {
+               dns_adbfind_t *find = NULL;
+               size_t maxaddrs = max_delegation_servers - *ns_processed;
+               size_t findlen = 0;
+
+               if (*ns_processed >= max_delegation_servers) {
+                       break;
+               }
+
+               if (deleg->type != DNS_DELEGTYPE_DELEG_ADDRESSES &&
+                   deleg->type != DNS_DELEGTYPE_NS_GLUES)
+               {
+                       continue;
+               }
+
+               if (ISC_LIST_EMPTY(deleg->addresses)) {
+                       continue;
+               }
+
+               fetchctx_ref(fctx);
+               dns_adb_createaddrinfosfind(fctx->adb, &deleg->addresses,
+                                           fctx->res->view->dstport, options,
+                                           now, maxaddrs, &find, &findlen);
+
+               if (find == NULL) {
+                       fetchctx_unref(fctx);
+                       break;
+               }
+
+               if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) {
+                       *allspilledp = true;
+                       fctx->quotacount++;
+               }
+
+               if (ISC_LIST_EMPTY(find->list)) {
+                       fetchctx_unref(fctx);
+                       dns_adb_destroyfind(&find);
+                       break;
+               }
+
+               *ns_processed += findlen;
+               INSIST(*ns_processed <= max_delegation_servers);
+               ISC_LIST_APPEND(finds, find, publink);
+       }
+
+       if (!ISC_LIST_EMPTY(finds)) {
+               ISC_LIST_APPENDLIST(fctx->finds, finds, publink);
+       }
+}
+
 static isc_result_t
 fctx_getaddresses_nameservers(fetchctx_t *fctx, isc_stdtime_t now,
                              unsigned int stdoptions, size_t fetches_allowed,
-                             bool *need_alternatep, bool *all_spilledp) {
+                             bool *need_alternatep, bool *all_spilledp,
+                             size_t *ns_processed) {
        bool have_address = false;
-       unsigned int ns_processed = 0;
-       uint32_t ns_processing_limit = fctx->res->view->max_delegation_servers;
-       dns_namelist_t *availablens = NULL;
+       unsigned int name_processed = 0;
        static thread_local dns_name_t *nameservers[MAX_DELEGATION_SERVERS];
+       size_t max_delegation_servers = fctx->res->view->max_delegation_servers;
 
        /*
-        * For now, only NS-based deleg is supported, and this can be only in a
-        * single list element.
+        * Lookup through each delegation for this zonecut (represented by
+        * `delegset`).
+        *
+        * If this is an NS-based delegation, each `deleg` represents an NS RR
+        * and will have a single server name.
+        *
+        * If this is a DELEG-based delegation, each `deleg` represents a DELEG
+        * RR and might have multiple server names.
         */
-       INSIST(ISC_LIST_HEAD(fctx->delegset->deleg) ==
-              ISC_LIST_TAIL(fctx->delegset->deleg));
-       availablens = &ISC_LIST_HEAD(fctx->delegset->deleg)->nameserver;
+       ISC_LIST_FOREACH(fctx->delegset->delegs, deleg, link) {
+               if (deleg->type != DNS_DELEGTYPE_DELEG_NAMES &&
+                   deleg->type != DNS_DELEGTYPE_NS_NAMES)
+               {
+                       continue;
+               }
 
-       ISC_LIST_FOREACH(*availablens, ns, link) {
-               nameservers[ns_processed] = ns;
+               if (ISC_LIST_EMPTY(deleg->names)) {
+                       continue;
+               }
 
-               if (++ns_processed >= ns_processing_limit) {
-                       break;
+               ISC_LIST_FOREACH(deleg->names, ns, link) {
+                       nameservers[name_processed++] = ns;
+
+                       if (name_processed >= max_delegation_servers) {
+                               goto shufflens;
+                       }
                }
        }
 
-       if (ns_processed > 1 && ns_processed > fetches_allowed) {
+shufflens:
+       if (name_processed > 1 && name_processed > fetches_allowed) {
                /*
                 * Skip the shuffle if:
                 * - there's nothing to shuffle (no or one nameserver)
                 * - there are less nameserver than allowed fetches as
                 *   we are going to start fetches for all of them.
                 */
-               for (size_t i = 0; i < ns_processed - 1; i++) {
-                       size_t j = i + isc_random_uniform(ns_processed - i);
+               for (size_t i = 0; i < name_processed - 1; i++) {
+                       size_t j = i + isc_random_uniform(name_processed - i);
 
                        ISC_SWAP(nameservers[i], nameservers[j]);
                }
        }
 
-       for (size_t i = 0; i < ns_processed; i++) {
+       for (size_t i = 0; i < name_processed; i++) {
                bool overquota = false;
                unsigned int static_stub = 0;
                unsigned int no_fetch = 0;
@@ -3720,6 +3796,10 @@ fctx_getaddresses_nameservers(fetchctx_t *fctx, isc_stdtime_t now,
                if (!overquota) {
                        *all_spilledp = false;
                }
+
+               if (++(*ns_processed) >= max_delegation_servers) {
+                       break;
+               }
        }
 
        if (fctx->pending_running == 0 && !have_address) {
@@ -3782,6 +3862,7 @@ fctx_getaddresses(fetchctx_t *fctx) {
        bool need_alternate = false;
        bool all_spilled = false;
        size_t fetches_allowed = 0;
+       size_t ns_processed = 0;
 
        FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth);
 
@@ -3867,25 +3948,45 @@ fctx_getaddresses(fetchctx_t *fctx) {
        }
 
        now = isc_stdtime_now();
-       all_spilled = true; /* resets to false below after the first success */
 
        INSIST(ISC_LIST_EMPTY(fctx->finds));
        INSIST(ISC_LIST_EMPTY(fctx->altfinds));
 
+       /*
+        * A dns_delegset_t can only have either
+        *
+        * - addresses (either from DELEG-based delegation with only addresses,
+        *   or NS-based delegation with glues)
+        * - name servers to lookup (either from DELEG-based delegation with
+        *   only name servers, or NS-based delegation without glues)
+        * - include-delegparam (from DELEG-based delegation only -- NYI).
+        *
+        * So let's try in this order. If nothing's found, then we can attempt
+        * alternates.
+        *
+        * Either way, the maximum number of nameserver names and addresses used
+        * for this resolution is at most `max_delegation_servers`. This is why
+        * `ns_processed` is shared with `fctx_getaddresses_addresses` and
+        * `fctx_getaddresses_nameservers`.
+        * */
+
+       fctx_getaddresses_addresses(fctx, now, stdoptions, &all_spilled,
+                                   &ns_processed);
+
        fetches_allowed = fctx_getaddresses_allowed(fctx);
 
        result = fctx_getaddresses_nameservers(fctx, now, stdoptions,
                                               fetches_allowed, &need_alternate,
-                                              &all_spilled);
+                                              &all_spilled, &ns_processed);
        if (result == DNS_R_CONTINUE && fetches_allowed == 0) {
                /*
                 * We have no addresses and we haven't allowed any
                 * fetches to be started.  Allow one extra fetch and try
                 * again.
                 */
-               (void)fctx_getaddresses_nameservers(fctx, now, stdoptions, 1,
-                                                   &need_alternate,
-                                                   &all_spilled);
+               (void)fctx_getaddresses_nameservers(
+                       fctx, now, stdoptions, 1, &need_alternate, &all_spilled,
+                       &ns_processed);
        }
 
        /*
@@ -6229,15 +6330,13 @@ cleanup:
 
 static isc_result_t
 rctx_cachemessage(respctx_t *rctx) {
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        fetchctx_t *fctx = rctx->fctx;
        resquery_t *query = rctx->query;
        dns_message_t *message = query->rmessage;
 
        FCTXTRACE("rctx_cachemessage");
 
-       FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTCACHE);
-
        LOCK(&fctx->lock);
 
        for (dns_section_t section = DNS_SECTION_ANSWER;
@@ -6250,6 +6349,8 @@ rctx_cachemessage(respctx_t *rctx) {
                }
        }
 
+       FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTCACHE);
+
 cleanup:
        UNLOCK(&fctx->lock);
        return result;
@@ -9136,26 +9237,6 @@ rctx_referral(respctx_t *rctx) {
                return ISC_R_COMPLETE;
        }
 
-       /*
-        * Mark any additional data related to this rdataset.
-        * It's important that we do this before we change the
-        * query domain.
-        */
-       INSIST(rctx->ns_rdataset != NULL);
-       FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
-       /*
-        * We want to append **all** the GLUE records here.
-        */
-       (void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name,
-                                         check_related, rctx, 0);
-       FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING);
-
-       /*
-        * An NS-based delegation can be cached immediately (i.e. there is
-        * no DNSSEC validation).
-        */
-       cache_delegns(rctx);
-
        /*
         * NS rdatasets with 0 TTL cause problems.
         * dns_view_findzonecut() will not find them when we
@@ -9167,6 +9248,17 @@ rctx_referral(respctx_t *rctx) {
                rctx->ns_rdataset->ttl = 1;
        }
 
+       /*
+        * An NS-based delegation can be cached immediately (i.e. there is no
+        * DNSSEC validation).
+        *
+        * For now we don't do anything if the delegation already exists and is
+        * not expired in the DB. Might be worth a warning? This should never
+        * happen.
+        */
+       INSIST(rctx->ns_rdataset != NULL);
+       (void)cache_delegns(rctx);
+
        /*
         * Set the current query domain to the referral name.
         *
@@ -9192,7 +9284,13 @@ rctx_referral(respctx_t *rctx) {
                return ISC_R_COMPLETE;
        }
 
+       /*
+        * While NS and glue records in referral responses are stored in the
+        * delegation database and not the main cache, other records, such as
+        * DS, do still need to be stored in the main cache.
+        */
        FCTX_ATTR_SET(fctx, FCTX_ATTR_WANTCACHE);
+
        fctx->ns_ttl_ok = false;
        log_ns_ttl(fctx, "DELEGATION");
        rctx->result = DNS_R_DELEGATION;