From: Colin Vidal Date: Thu, 5 Feb 2026 08:46:01 +0000 (+0100) Subject: Limit the number of addresses returned per ADB find X-Git-Tag: v9.21.22~9^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e986b19d0d61aa87348fe509933cadd5a05f24c9;p=thirdparty%2Fbind9.git Limit the number of addresses returned per ADB find 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). --- diff --git a/lib/dns/adb.c b/lib/dns/adb.c index f189664f80c..f51b2a88216 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -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)) { diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 7c1aef4cc5d..82abbf98f57 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -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 diff --git a/lib/dns/notify.c b/lib/dns/notify.c index 46766ea7115..3b2ec98f5da 100644 --- a/lib/dns/notify.c +++ b/lib/dns/notify.c @@ -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, - ¬ify->ns, options, 0, notify->port, 0, - NULL, NULL, NULL, ¬ify->find); + result = dns_adb_createfind( + adb, loop, process_notify_adb_event, notify, ¬ify->ns, + options, 0, notify->port, 0, NULL, NULL, NULL, + view->max_delegation_servers, ¬ify->find, NULL); dns_adb_detach(&adb); /* Something failed? */ diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 742748d2f3f..ba487961894 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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) { diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 3414ed8d356..4ab816c1f2a 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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? */