]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Limit the number of addresses returned per ADB find
authorColin Vidal <colin@isc.org>
Thu, 5 Feb 2026 08:46:01 +0000 (09:46 +0100)
committerMichał Kępień <michal@isc.org>
Thu, 7 May 2026 11:32:15 +0000 (13:32 +0200)
The number of `dns_adbaddrfind_t` (NS address with metadata like SRTT)
returned from an ADB NS name lookup is now limited by the caller. The
default value (outside the resolver) uses `max-delegation-servers`, and
the resolver, for a given fetch, start with `max-delegation-servers` and
decrement it at each ADB fetch. This ensures that, for a given
delegation, no more than 13 nameservers will be contacted.

This is the same mechanism used when looking up `dns_adbaddrfind_t` from
a list of glues (addresses).

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

index f189664f80c5d82c4d2df4769328437e506222ce..f51b2a88216a0af7c28a13e0d15152e448bf6001 100644 (file)
@@ -1370,8 +1370,10 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) {
 }
 
 static void
-copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
+copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name,
+                   size_t maxfindlen, size_t *findlen) {
        dns_adbentry_t *entry = NULL;
+       size_t count = 0;
 
        if ((find->options & DNS_ADBFIND_INET) != 0) {
                ISC_LIST_FOREACH(name->v4, namehook, name_link) {
@@ -1391,6 +1393,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
                         * Found a valid entry.  Add it to the find's list.
                         */
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+
+                       count++;
+                       if (maxfindlen - count == 0) {
+                               SET_IF_NOT_NULL(findlen, count);
+                               return;
+                       }
                }
        }
 
@@ -1412,8 +1420,16 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
                         * Found a valid entry.  Add it to the find's list.
                         */
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+
+                       count++;
+                       if (maxfindlen - count == 0) {
+                               SET_IF_NOT_NULL(findlen, count);
+                               return;
+                       }
                }
        }
+
+       SET_IF_NOT_NULL(findlen, count);
 }
 
 static bool
@@ -1735,7 +1751,7 @@ out:
 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,
+                           isc_stdtime_t now, size_t maxfindlen,
                            dns_adbfind_t **findp, size_t *findlen) {
        dns_adbfind_t *find = NULL;
        isc_sockaddr_t sockaddr = {};
@@ -1743,7 +1759,7 @@ dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(addrs != NULL);
        REQUIRE(findp != NULL && *findp == NULL);
-       REQUIRE(maxaddrs > 0);
+       REQUIRE(maxfindlen > 0);
 
        rcu_read_lock();
 
@@ -1794,7 +1810,7 @@ dns_adb_createaddrinfosfind(dns_adb_t *adb, isc_netaddrlist_t *addrs,
                ISC_LIST_APPEND(find->list, addrinfo, publink);
                (*findlen)++;
 
-               if (maxaddrs - *findlen == 0) {
+               if (maxfindlen - *findlen == 0) {
                        break;
                }
        }
@@ -1825,7 +1841,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg,
                   const dns_name_t *name, unsigned int options,
                   isc_stdtime_t now, in_port_t port, unsigned int depth,
                   isc_counter_t *qc, isc_counter_t *gqc, fetchctx_t *parent,
-                  dns_adbfind_t **findp) {
+                  size_t maxfindlen, dns_adbfind_t **findp, size_t *findlen) {
        isc_result_t result = ISC_R_UNEXPECTED;
        dns_adbfind_t *find = NULL;
        dns_adbname_t *adbname = NULL;
@@ -1844,6 +1860,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg,
        }
        REQUIRE(name != NULL);
        REQUIRE(findp != NULL && *findp == NULL);
+       REQUIRE(maxfindlen > 0);
 
        REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
 
@@ -2056,7 +2073,7 @@ fetch:
         * Run through the name and copy out the bits we are
         * interested in.
         */
-       copy_namehook_lists(adb, find, adbname);
+       copy_namehook_lists(adb, find, adbname, maxfindlen, findlen);
 
 post_copy:
        if (NAME_FETCH_A(adbname)) {
index 7c1aef4cc5d831a32ef8856c63cb58c9ac8c402d..82abbf98f573c9d006ff501062d3e80726205e6f 100644 (file)
@@ -285,7 +285,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg,
                   const dns_name_t *name, unsigned int options,
                   isc_stdtime_t now, in_port_t port, unsigned int depth,
                   isc_counter_t *qc, isc_counter_t *gqc, fetchctx_t *parent,
-                  dns_adbfind_t **find);
+                  size_t maxfindlen, dns_adbfind_t **find, size_t *findlen);
 /*%<
  * Main interface for clients. The adb will look up the name given in
  * "name" and will build up a list of found addresses, and perhaps start
@@ -333,6 +333,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg,
  *
  *\li  find != NULL && *find == NULL.
  *
+ *\li   findlen is optional, if not NULL, it will be set to the length of find.
+ *
  * Returns:
  *
  *\li  #ISC_R_SUCCESS  Addresses might have been returned, and events will be
index 46766ea7115e073abf2aa824be66b5b1a3c10096..3b2ec98f5daf34ee2756578ef30abd3951439d51 100644 (file)
@@ -761,9 +761,10 @@ dns_notify_find_address(dns_notify_t *notify) {
                goto destroy;
        }
 
-       result = dns_adb_createfind(adb, loop, process_notify_adb_event, notify,
-                                   &notify->ns, options, 0, notify->port, 0,
-                                   NULL, NULL, NULL, &notify->find);
+       result = dns_adb_createfind(
+               adb, loop, process_notify_adb_event, notify, &notify->ns,
+               options, 0, notify->port, 0, NULL, NULL, NULL,
+               view->max_delegation_servers, &notify->find, NULL);
        dns_adb_detach(&adb);
 
        /* Something failed? */
index 742748d2f3f1fabe877ecb460e342656358885b8..ba487961894d8ae36c2026ec7efbb569330f21dc 100644 (file)
@@ -3375,7 +3375,8 @@ already_waiting_for(dns_adbfind_t *find, dns_rdatatype_t type) {
 static void
 findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
         unsigned int options, unsigned int flags, isc_stdtime_t now,
-        bool *overquota, bool *need_alternate, bool *have_address) {
+        bool *overquota, bool *need_alternate, bool *have_address,
+        size_t maxfindlen, size_t *findlen) {
        dns_adbfind_t *find = NULL;
        dns_resolver_t *res = fctx->res;
        bool unshared = ((fctx->options & DNS_FETCHOPT_UNSHARED) != 0);
@@ -3416,7 +3417,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
        result = dns_adb_createfind(fctx->adb, fctx->loop, fctx_finddone, fctx,
                                    name, options, now, res->view->dstport,
                                    fctx->depth + 1, fctx->qc, fctx->gqc, fctx,
-                                   &find);
+                                   maxfindlen, &find, findlen);
 
        isc_log_write(DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
                      ISC_LOG_DEBUG(3), "fctx %p(%s): createfind for %s - %s",
@@ -3670,7 +3671,7 @@ fctx_getaddresses_addresses(fetchctx_t *fctx, isc_stdtime_t now,
 
        ISC_LIST_FOREACH(fctx->delegset->delegs, deleg, link) {
                dns_adbfind_t *find = NULL;
-               size_t maxaddrs = max_delegation_servers - *ns_processed;
+               size_t maxfindlen = max_delegation_servers - *ns_processed;
                size_t findlen = 0;
 
                if (*ns_processed >= max_delegation_servers) {
@@ -3690,7 +3691,7 @@ fctx_getaddresses_addresses(fetchctx_t *fctx, isc_stdtime_t now,
                fetchctx_ref(fctx);
                dns_adb_createaddrinfosfind(fctx->adb, &deleg->addresses,
                                            fctx->res->view->dstport, options,
-                                           now, maxaddrs, &find, &findlen);
+                                           now, maxfindlen, &find, &findlen);
 
                if (find == NULL) {
                        fetchctx_unref(fctx);
@@ -3778,6 +3779,12 @@ shufflens:
                unsigned int static_stub = 0;
                unsigned int no_fetch = 0;
                dns_name_t *ns = nameservers[i];
+               size_t maxfindlen = max_delegation_servers - *ns_processed;
+               size_t findlen = 0;
+
+               if (*ns_processed >= max_delegation_servers) {
+                       break;
+               }
 
                if (fctx->delegset->staticstub &&
                    dns_name_equal(ns, fctx->domain))
@@ -3794,15 +3801,15 @@ shufflens:
                }
 
                findname(fctx, ns, 0, stdoptions | static_stub | no_fetch, 0,
-                        now, &overquota, need_alternatep, &have_address);
+                        now, &overquota, need_alternatep, &have_address,
+                        maxfindlen, &findlen);
 
                if (!overquota) {
                        *all_spilledp = false;
                }
+               *ns_processed += findlen;
 
-               if (++(*ns_processed) >= max_delegation_servers) {
-                       break;
-               }
+               INSIST(*ns_processed <= max_delegation_servers);
        }
 
        if (fctx->pending_running == 0 && !have_address) {
@@ -3828,7 +3835,8 @@ fctx_getaddresses_alternate(fetchctx_t *fctx, isc_stdtime_t now,
                if (!a->isaddress) {
                        findname(fctx, &a->_u._n.name, a->_u._n.port,
                                 stdoptions, FCTX_ADDRINFO_DUALSTACK, now, NULL,
-                                NULL, NULL);
+                                NULL, NULL,
+                                fctx->res->view->max_delegation_servers, NULL);
                        continue;
                }
                if (isc_sockaddr_pf(&a->_u.addr) != family) {
index 3414ed8d356b0f214b11cf70cbbfc5d2726a1e2a..4ab816c1f2a2007d84fd55975f41ab3a6043b362 100644 (file)
@@ -17278,9 +17278,11 @@ checkds_find_address(dns_checkds_t *checkds) {
        isc_result_t result;
        unsigned int options;
        dns_adb_t *adb = NULL;
+       dns_view_t *view = NULL;
 
        REQUIRE(DNS_CHECKDS_VALID(checkds));
 
+       view = checkds->zone->view;
        options = DNS_ADBFIND_WANTEVENT;
        if (isc_net_probeipv4() != ISC_R_DISABLED) {
                options |= DNS_ADBFIND_INET;
@@ -17289,7 +17291,7 @@ checkds_find_address(dns_checkds_t *checkds) {
                options |= DNS_ADBFIND_INET6;
        }
 
-       dns_view_getadb(checkds->zone->view, &adb);
+       dns_view_getadb(view, &adb);
        if (adb == NULL) {
                goto destroy;
        }
@@ -17297,7 +17299,7 @@ checkds_find_address(dns_checkds_t *checkds) {
        result = dns_adb_createfind(
                adb, checkds->zone->loop, process_checkds_adb_event, checkds,
                &checkds->ns, options, 0, checkds->zone->view->dstport, 0, NULL,
-               NULL, NULL, &checkds->find);
+               NULL, NULL, view->max_delegation_servers, &checkds->find, NULL);
        dns_adb_detach(&adb);
 
        /* Something failed? */