From 80316efdd2e6b2128cbb04dfa6eab51fba5e06f9 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 19 Dec 2025 18:12:06 +1100 Subject: [PATCH] Remove determinist selection of nameserver When selecting nameserver addresses to be looked up we where always selecting them in dnssec name order from the start of the nameserver rrset. This could lead to resolution failure despite there being address that could be resolved for the other names. Use a random starting point when selecting which names to lookup. (cherry picked from commit b78052119ab3f0355eeb9fb9a9ec199084fc186a) --- lib/dns/resolver.c | 98 +++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 7d244792b6..1557aef2e8 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -3658,58 +3658,74 @@ normal_nses: } for (;;) { - for (result = dns_rdataset_first(&fctx->nameservers); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&fctx->nameservers)) - { - dns_rdata_t rdata = DNS_RDATA_INIT; - bool overquota = false; - unsigned int static_stub = 0; - unsigned int no_fetch = 0; + size_t nscount = dns_rdataset_count(&fctx->nameservers); + size_t maxstartns = nscount > NS_PROCESSING_LIMIT + ? NS_PROCESSING_LIMIT + : nscount; + size_t startns = isc_random_uniform(maxstartns); - dns_rdataset_current(&fctx->nameservers, &rdata); - /* - * Extract the name from the NS record. - */ - result = dns_rdata_tostruct(&rdata, &ns, NULL); - if (result != ISC_R_SUCCESS) { - continue; - } + for (size_t pass = 0; pass < 2; pass++) { + size_t curns = 0; - if (STATICSTUB(&fctx->nameservers) && - dns_name_equal(&ns.name, fctx->domain)) + for (result = dns_rdataset_first(&fctx->nameservers); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&fctx->nameservers)) { - static_stub = DNS_ADBFIND_STATICSTUB; - } + dns_rdata_t rdata = DNS_RDATA_INIT; + bool overquota = false; + unsigned int static_stub = 0; + unsigned int no_fetch = 0; - /* - * Make sure we only launch a limited number of - * outgoing fetches. - */ - if (fctx->pending_running >= fetches_allowed) { - no_fetch = DNS_ADBFIND_NOFETCH; - } + if (pass == 0 && curns++ < startns) { + continue; + } + if (pass == 1 && curns++ >= startns) { + break; + } - findname(fctx, &ns.name, 0, - stdoptions | static_stub | no_fetch, 0, now, - &overquota, &need_alternate, &have_address); + dns_rdataset_current(&fctx->nameservers, + &rdata); + /* + * Extract the name from the NS record. + */ + result = dns_rdata_tostruct(&rdata, &ns, NULL); + if (result != ISC_R_SUCCESS) { + continue; + } - if (!overquota) { - all_spilled = false; - } + if (STATICSTUB(&fctx->nameservers) && + dns_name_equal(&ns.name, fctx->domain)) + { + static_stub = DNS_ADBFIND_STATICSTUB; + } - dns_rdata_reset(&rdata); - dns_rdata_freestruct(&ns); + /* + * Make sure we only launch a limited number of + * outgoing fetches. + */ + if (fctx->pending_running >= fetches_allowed) { + no_fetch = DNS_ADBFIND_NOFETCH; + } - if (++ns_processed >= NS_PROCESSING_LIMIT) { - result = ISC_R_NOMORE; - break; + findname(fctx, &ns.name, 0, + stdoptions | static_stub | no_fetch, 0, + now, &overquota, &need_alternate, + &have_address); + + if (!overquota) { + all_spilled = false; + } + + dns_rdata_reset(&rdata); + dns_rdata_freestruct(&ns); + + if (++ns_processed >= NS_PROCESSING_LIMIT) { + result = ISC_R_NOMORE; + break; + } } } - /* - * Don't start alternate fetch if we just started one above. - */ /* * Don't start alternate fetch if we just started one above. */