From 47956de897de02c3a3631588d73b23cf68b22e48 Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Mon, 27 May 2024 13:53:16 +0200 Subject: [PATCH] - Fix to enable that SERVFAIL is cached, for a short period, for more cases. In the cases where limits are exceeded. --- doc/Changelog | 4 +++ iterator/iterator.c | 68 +++++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 4b430c4f9..5b7cba5bc 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +27 May 2024: Wouter + - Fix to enable that SERVFAIL is cached, for a short period, for more + cases. In the cases where limits are exceeded. + 24 May 2024: Wouter - Fix #1064: Unbound 1.20 Cachedb broken? diff --git a/iterator/iterator.c b/iterator/iterator.c index 7863e7214..5a99ab0d7 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1378,7 +1378,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, "restarts (eg. indirections)"); if(iq->qchase.qname) errinf_dname(qstate, "stop at", iq->qchase.qname); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } /* We enforce a maximum recursion/dependency depth -- in general, @@ -1654,7 +1654,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(!iq->dp) { log_err("internal error: no hints dp"); errinf(qstate, "no hints for this class"); - return error_response(qstate, id, + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->dp = delegpt_copy(iq->dp, qstate->region); @@ -1974,7 +1974,8 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq, * if it is negative, there is no maximum number of targets. * @param num: returns the number of queries generated and processed, * which may be zero if there were no missing targets. - * @return false on error. + * @return 0 on success, nonzero on error. 1 means temporary failure and + * 2 means the failure can be cached. */ static int query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, @@ -1997,13 +1998,13 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, else toget = maxtargets; if(toget == 0) { *num = 0; - return 1; + return 0; } /* now that we are sure that a target query is going to be made, * check the limits. */ if(iq->depth == ie->max_dependency_depth) - return 0; + return 1; if(iq->depth > 0 && iq->target_count && iq->target_count[TARGET_COUNT_QUERIES] > MAX_TARGET_COUNT) { char s[LDNS_MAX_DOMAINLEN+1]; @@ -2011,7 +2012,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_QUERY, "request %s has exceeded the maximum " "number of glue fetches %d", s, iq->target_count[TARGET_COUNT_QUERIES]); - return 0; + return 2; } if(iq->dp_target_count > MAX_DP_TARGET_COUNT) { char s[LDNS_MAX_DOMAINLEN+1]; @@ -2019,7 +2020,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_QUERY, "request %s has exceeded the maximum " "number of glue fetches %d to a single delegation point", s, iq->dp_target_count); - return 0; + return 2; } /* select 'toget' items from the total of 'missing' items */ @@ -2048,7 +2049,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, *num = query_count; if(query_count > 0) qstate->ext_state[id] = module_wait_subquery; - return 0; + return 1; } query_count++; /* If the mesh query list is full, exit the loop here. @@ -2078,7 +2079,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, *num = query_count; if(query_count > 0) qstate->ext_state[id] = module_wait_subquery; - return 0; + return 1; } query_count++; /* If the mesh query list is full, exit the loop. */ @@ -2102,7 +2103,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, if(query_count > 0) qstate->ext_state[id] = module_wait_subquery; - return 1; + return 0; } /** @@ -2193,12 +2194,14 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, } /* query for an extra name added by the parent-NS record */ if(delegpt_count_missing_targets(iq->dp, NULL) > 0) { - int qs = 0; + int qs = 0, ret; verbose(VERB_ALGO, "try parent-side target name"); - if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) { + if((ret=query_for_targets(qstate, iq, ie, id, 1, &qs))!=0) { errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + if(ret == 1) + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; target_count_increase(iq, qs); @@ -2427,13 +2430,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_QUERY, "request has exceeded the maximum " "number of referrrals with %d", iq->referral_count); errinf(qstate, "exceeded the maximum of referrals"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(iq->sent_count > ie->max_sent_count) { verbose(VERB_QUERY, "request has exceeded the maximum " "number of sends with %d", iq->sent_count); errinf(qstate, "exceeded the maximum number of sends"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } /* Check if we reached MAX_TARGET_NX limit without a fallback activation. */ @@ -2463,7 +2466,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "already present for the delegation point, no " "fallback possible"); errinf(qstate, "exceeded the maximum nameserver nxdomains"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } verbose(VERB_ALGO, "initiating parent-side fallback for " "nxdomain nameserver lookups"); @@ -2506,7 +2509,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "lookups (%d) with %d", MAX_TARGET_NX_FALLBACK, iq->target_count[TARGET_COUNT_NX]); errinf(qstate, "exceeded the maximum nameserver nxdomains"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(!iq->dp->has_parent_side_NS) { @@ -2720,7 +2723,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_ALGO, "auth zone lookup failed, no fallback," " servfail"); errinf(qstate, "auth zone lookup failed, fallback is off"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(iq->dp->auth_dp) { /* we wanted to fallback, but had no delegpt, only the @@ -2749,11 +2752,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* if in 0x20 fallback get as many targets as possible */ if(iq->caps_fallback) { - int extra = 0; + int extra = 0, ret; size_t naddr, nres, navail; - if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) { + if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) { errinf(qstate, "could not fetch nameservers for 0x20 fallback"); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + if(ret == 1) + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; target_count_increase(iq, extra); @@ -2896,14 +2901,17 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * to distinguish between generating (a) new target * query, or failing. */ if(delegpt_count_missing_targets(iq->dp, NULL) > 0) { - int qs = 0; + int qs = 0, ret; verbose(VERB_ALGO, "querying for next " "missing target"); - if(!query_for_targets(qstate, iq, ie, id, - 1, &qs)) { + if((ret=query_for_targets(qstate, iq, ie, id, + 1, &qs))!=0) { errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); - return error_response(qstate, id, + if(ret == 1) + return error_response(qstate, id, + LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(qs == 0 && @@ -3049,7 +3057,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, qstate->was_ratelimited = 1; errinf_dname(qstate, "exceeded ratelimit for zone", iq->dp->name); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } log_addr(VERB_QUERY, "error sending query to auth server", &real_addr, real_addrlen); @@ -3271,7 +3279,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iter_scrub_nxdomain(iq->response); return final_state(iq); } - return error_response(qstate, id, + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } /* Best effort qname-minimisation. @@ -3606,7 +3614,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, " fallback possible, servfail"); errinf_dname(qstate, "response is bad, no fallback, " "for auth zone", iq->dp->name); - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } verbose(VERB_ALGO, "auth zone response was bad, " "fallback enabled"); @@ -4014,7 +4022,7 @@ processCollectClass(struct module_qstate* qstate, int id) if(iq->num_current_queries == 0) { verbose(VERB_ALGO, "No root hints or fwds, giving up " "on qclass ANY"); - return error_response(qstate, id, LDNS_RCODE_REFUSED); + return error_response_cache(qstate, id, LDNS_RCODE_REFUSED); } /* return false, wait for queries to return */ } @@ -4381,7 +4389,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, "getting different replies, failed"); outbound_list_remove(&iq->outlist, outbound); errinf(qstate, "0x20 failed, then got different replies in fallback"); - (void)error_response(qstate, id, + (void)error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); return; } -- 2.47.2