diff --git a/lib/dns/adb.c b/lib/dns/adb.c index a2800226d1..8df418d189 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -440,6 +440,7 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) +#define FIND_NOFETCH(fn) (((fn)->options & DNS_ADBFIND_NOFETCH) != 0) /* * These are currently used on simple unsigned ints, so they are @@ -3234,7 +3235,9 @@ fetch: } else { have_address = false; } - if (wanted_fetches != 0 && !(FIND_AVOIDFETCHES(find) && have_address)) { + if (wanted_fetches != 0 && !(FIND_AVOIDFETCHES(find) && have_address) && + !FIND_NOFETCH(find)) + { /* * We're missing at least one address family. Either the * caller hasn't instructed us to avoid fetches, or we don't diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 5895b5db3a..724f9b001a 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -205,6 +205,10 @@ struct dns_adbfind { * lame for this query. */ #define DNS_ADBFIND_OVERQUOTA 0x00000400 +/*% + * Don't perform a fetch even if there are no address records available. + */ +#define DNS_ADBFIND_NOFETCH 0x00000800 /*% * The answers to queries come back as a list of these. diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 80203d95e1..ed3ad58eaf 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -183,6 +183,14 @@ #define DEFAULT_MAX_QUERIES 75 #endif /* ifndef DEFAULT_MAX_QUERIES */ +/* + * After NS_FAIL_LIMIT attempts to fetch a name server address, + * if the number of addresses in the NS RRset exceeds NS_RR_LIMIT, + * stop trying to fetch, in order to avoid wasting resources. + */ +#define NS_FAIL_LIMIT 4 +#define NS_RR_LIMIT 5 + /* Number of hash buckets for zone counters */ #ifndef RES_DOMAIN_BUCKETS #define RES_DOMAIN_BUCKETS 523 @@ -3465,7 +3473,7 @@ sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) { 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 *overquota, bool *need_alternate, unsigned int *no_addresses) { dns_adbaddrinfo_t *ai; dns_adbfind_t *find; dns_resolver_t *res; @@ -3562,6 +3570,9 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, { *need_alternate = true; } + if (no_addresses != NULL) { + (*no_addresses)++; + } } else { if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) { if (overquota != NULL) { @@ -3616,6 +3627,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { dns_rdata_ns_t ns; bool need_alternate = false; bool all_spilled = true; + unsigned int no_addresses = 0; FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth); @@ -3792,8 +3804,13 @@ normal_nses: continue; } + if (no_addresses > NS_FAIL_LIMIT && + dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT) + { + stdoptions |= DNS_ADBFIND_NOFETCH; + } findname(fctx, &ns.name, 0, stdoptions, 0, now, &overquota, - &need_alternate); + &need_alternate, &no_addresses); if (!overquota) { all_spilled = false; @@ -3818,7 +3835,7 @@ normal_nses: if (!a->isaddress) { findname(fctx, &a->_u._n.name, a->_u._n.port, stdoptions, FCTX_ADDRINFO_FORWARDER, - now, NULL, NULL); + now, NULL, NULL, NULL); continue; } if (isc_sockaddr_pf(&a->_u.addr) != family) {