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.)
This commit is contained in:
Colin Vidal 2026-03-30 11:45:15 +02:00
parent cfac5f3974
commit 6ed7a8a723
3 changed files with 162 additions and 54 deletions

View 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();

View 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,

View 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;