From: Colin Vidal Date: Mon, 30 Mar 2026 09:45:15 +0000 (+0200) Subject: Resolver is parent-centric X-Git-Tag: v9.21.21~4^2~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6ed7a8a72359d360cc3539abe2ffdf1541d6d072;p=thirdparty%2Fbind9.git Resolver is parent-centric 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.) --- diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 6c02ed86a46..341f9c96cda 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -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(); diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 157f8da0b2b..cce3970df55 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -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, diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index fdba1430191..84da407be50 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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;