diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-09-10 16:32:55 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-09-10 16:32:55 +0000 |
commit | dcaa814d350c5ee7deb2164502a24f2f698b9799 (patch) | |
tree | 9cb62373e6c424da021043a171564ced3bb19501 /iterator | |
parent | 4aea2433fa04a7a86c8972869bd021b7a3622dc8 (diff) | |
download | src-dcaa814d350c5ee7deb2164502a24f2f698b9799.tar.gz src-dcaa814d350c5ee7deb2164502a24f2f698b9799.zip |
Vendor import of Unbound 1.8.0.vendor/unbound/1.8.0
Notes
Notes:
svn path=/vendor/unbound/dist/; revision=338566
svn path=/vendor/unbound/1.8.0/; revision=338567; tag=vendor/unbound/1.8.0
Diffstat (limited to 'iterator')
-rw-r--r-- | iterator/iter_delegpt.h | 2 | ||||
-rw-r--r-- | iterator/iter_fwd.c | 7 | ||||
-rw-r--r-- | iterator/iter_hints.c | 7 | ||||
-rw-r--r-- | iterator/iter_utils.c | 26 | ||||
-rw-r--r-- | iterator/iterator.c | 189 | ||||
-rw-r--r-- | iterator/iterator.h | 3 |
6 files changed, 223 insertions, 11 deletions
diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index 354bd6177380..6c088264588f 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -85,6 +85,8 @@ struct delegpt { uint8_t ssl_upstream; /** delegpt from authoritative zone that is locally hosted */ uint8_t auth_dp; + /*** no cache */ + int no_cache; }; /** diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index a44f54386dc4..4eb0eb718607 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -239,6 +239,11 @@ read_fwds_addr(struct config_stub* s, struct delegpt* dp) s->name, p->str); return 0; } +#ifndef HAVE_SSL_SET1_HOST + if(tls_auth_name) + log_err("no name verification functionality in " + "ssl library, ignored name for %s", p->str); +#endif if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0, tls_auth_name)) { log_err("out of memory"); @@ -267,6 +272,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg) * last resort will ask for parent-side NS record and thus * fallback to the internet name servers on a failure */ dp->has_parent_side_NS = (uint8_t)!s->isfirst; + /* Do not cache if set. */ + dp->no_cache = s->no_cache; /* use SSL for queries to this forwarder */ dp->ssl_upstream = (uint8_t)s->ssl_upstream; verbose(VERB_QUERY, "Forward zone server list:"); diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index e8d09338e974..0b35a9d9e24f 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -252,6 +252,11 @@ read_stubs_addr(struct config_stub* s, struct delegpt* dp) s->name, p->str); return 0; } +#ifndef HAVE_SSL_SET1_HOST + if(auth_name) + log_err("no name verification functionality in " + "ssl library, ignored name for %s", p->str); +#endif if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0, auth_name)) { log_err("out of memory"); @@ -278,6 +283,8 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg) * last resort will ask for parent-side NS record and thus * fallback to the internet name servers on a failure */ dp->has_parent_side_NS = (uint8_t)!s->isfirst; + /* Do not cache if set. */ + dp->no_cache = s->no_cache; /* ssl_upstream */ dp->ssl_upstream = (uint8_t)s->ssl_upstream; delegpt_log(VERB_QUERY, dp); diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 0a8f7700fcf0..90c8cf114e33 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -375,11 +375,34 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, int got_num6 = 0; int low_rtt6 = 0; int i; + int attempt = -1; /* filter to make sure addresses have + less attempts on them than the first, to force round + robin when all the IPv6 addresses fail */ + int num4ok = 0; /* number ip4 at low attempt count */ + int num4_lowrtt = 0; prev = NULL; a = dp->result_list; for(i = 0; i < got_num; i++) { swap_to_front = 0; + if(a->addr.ss_family != AF_INET6 && attempt == -1) { + /* if we only have ip4 at low attempt count, + * then ip6 is failing, and we need to + * select one of the remaining IPv4 addrs */ + attempt = a->attempts; + num4ok++; + num4_lowrtt = a->sel_rtt; + } else if(a->addr.ss_family != AF_INET6 && attempt == a->attempts) { + num4ok++; + if(num4_lowrtt == 0 || a->sel_rtt < num4_lowrtt) { + num4_lowrtt = a->sel_rtt; + } + } if(a->addr.ss_family == AF_INET6) { + if(attempt == -1) { + attempt = a->attempts; + } else if(a->attempts > attempt) { + break; + } got_num6++; swap_to_front = 1; if(low_rtt6 == 0 || a->sel_rtt < low_rtt6) { @@ -401,6 +424,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, if(got_num6 > 0) { got_num = got_num6; *selected_rtt = low_rtt6; + } else if(num4ok > 0) { + got_num = num4ok; + *selected_rtt = num4_lowrtt; } } return got_num; diff --git a/iterator/iterator.c b/iterator/iterator.c index 58a9bff6634c..e99a559fae4d 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -230,11 +230,12 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) qstate->qinfo.qname, qstate->qinfo.qname_len); if(!dpns) { /* not interested */ + /* this can happen, for eg. qname minimisation asked + * for an NXDOMAIN to be validated, and used qtype + * A for that, and the error of that, the name, is + * not listed in super_iq->dp */ verbose(VERB_ALGO, "subq error, but not interested"); log_query_info(VERB_ALGO, "superq", &super->qinfo); - if(super_iq->dp) - delegpt_log(VERB_ALGO, super_iq->dp); - log_assert(0); return; } else { /* see if the failure did get (parent-lame) info */ @@ -303,8 +304,20 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode) if((msg=msg_cache_lookup(qstate->env, qstate->qinfo.qname, qstate->qinfo.qname_len, qstate->qinfo.qtype, qstate->qinfo.qclass, - qstate->query_flags, 0, 0)) + qstate->query_flags, 0, + qstate->env->cfg->serve_expired_ttl_reset)) != NULL) { + if(qstate->env->cfg->serve_expired_ttl_reset) { + struct reply_info* rep = + (struct reply_info*)msg->entry.data; + if(rep && *qstate->env->now + + qstate->env->cfg->serve_expired_ttl > + rep->serve_expired_ttl) { + rep->serve_expired_ttl = + *qstate->env->now + + qstate->env->cfg->serve_expired_ttl; + } + } lock_rw_unlock(&msg->entry.lock); return error_response(qstate, id, rcode); } @@ -318,6 +331,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode) err.qdcount = 1; err.ttl = NORR_TTL; err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl); + err.serve_expired_ttl = NORR_TTL; /* do not waste time trying to validate this servfail */ err.security = sec_status_indeterminate; verbose(VERB_ALGO, "store error response in message cache"); @@ -789,6 +803,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, iq->dp = delegpt_copy(stub_dp, qstate->region); if(!iq->dp) { log_err("out of memory priming stub"); + errinf(qstate, "malloc failure, priming stub"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return 1; /* return 1 to make module stop, with error */ } @@ -807,6 +822,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, LDNS_RR_TYPE_NS, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0)) { verbose(VERB_ALGO, "could not prime stub"); + errinf(qstate, "could not generate lookup for stub prime"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return 1; /* return 1 to make module stop, with error */ } @@ -822,6 +838,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, fptr_ok(fptr_whitelist_modenv_kill_sub( qstate->env->kill_sub)); (*qstate->env->kill_sub)(subq); + errinf(qstate, "malloc failure, in stub prime"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return 1; /* return 1 to make module stop, with error */ } @@ -905,6 +922,7 @@ auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq, return 1; /* just fallback */ } lock_rw_unlock(&z->lock); + errinf(qstate, "malloc failure"); return 0; } dp->name = regional_alloc_init(qstate->region, @@ -916,6 +934,7 @@ auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq, return 1; /* just fallback */ } lock_rw_unlock(&z->lock); + errinf(qstate, "malloc failure"); return 0; } dp->namelen = z->namelen; @@ -1125,6 +1144,53 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq) return 1; } +static int +iter_stub_fwd_no_cache(struct module_qstate *qstate, struct iter_qstate *iq) +{ + struct iter_hints_stub *stub; + struct delegpt *dp; + + /* Check for stub. */ + stub = hints_lookup_stub(qstate->env->hints, iq->qchase.qname, + iq->qchase.qclass, iq->dp); + dp = forwards_lookup(qstate->env->fwds, iq->qchase.qname, iq->qchase.qclass); + + /* see if forward or stub is more pertinent */ + if(stub && stub->dp && dp) { + if(dname_strict_subdomain(dp->name, dp->namelabs, + stub->dp->name, stub->dp->namelabs)) { + stub = NULL; /* ignore stub, forward is lower */ + } else { + dp = NULL; /* ignore forward, stub is lower */ + } + } + + /* check stub */ + if (stub != NULL && stub->dp != NULL) { + if(stub->dp->no_cache) { + char qname[255+1]; + char dpname[255+1]; + dname_str(iq->qchase.qname, qname); + dname_str(stub->dp->name, dpname); + verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); + } + return (stub->dp->no_cache); + } + + /* Check for forward. */ + if (dp) { + if(dp->no_cache) { + char qname[255+1]; + char dpname[255+1]; + dname_str(iq->qchase.qname, qname); + dname_str(dp->name, dpname); + verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); + } + return (dp->no_cache); + } + return 0; +} + /** * Process the initial part of the request handling. This state roughly * corresponds to resolver algorithms steps 1 (find answer in cache) and 2 @@ -1159,6 +1225,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(iq->query_restart_count > MAX_RESTART_COUNT) { verbose(VERB_QUERY, "request has exceeded the maximum number" " of query restarts with %d", iq->query_restart_count); + errinf(qstate, "request has exceeded the maximum number " + "restarts (eg. indirections)"); + if(iq->qchase.qname) + errinf_dname(qstate, "stop at", iq->qchase.qname); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1170,6 +1240,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(iq->depth > ie->max_dependency_depth) { verbose(VERB_QUERY, "request has exceeded the maximum " "dependency depth with depth of %d", iq->depth); + errinf(qstate, "request has exceeded the maximum dependency " + "depth (eg. nameserver lookup recursion)"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1196,7 +1268,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* This either results in a query restart (CNAME cache response), a * terminating response (ANSWER), or a cache miss (null). */ - if(qstate->blacklist) { + if (iter_stub_fwd_no_cache(qstate, iq)) { + /* Asked to not query cache. */ + verbose(VERB_ALGO, "no-cache set, going to the network"); + qstate->no_cache_lookup = 1; + qstate->no_cache_store = 1; + msg = NULL; + } else if(qstate->blacklist) { /* if cache, or anything else, was blacklisted then * getting older results from cache is a bad idea, no cache */ verbose(VERB_ALGO, "cache blacklisted, going to the network"); @@ -1240,9 +1318,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_ALGO, "returning CNAME response from " "cache"); if(!handle_cname_response(qstate, iq, msg, - &sname, &slen)) + &sname, &slen)) { + errinf(qstate, "failed to prepend CNAME " + "components, malloc failure"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } iq->qchase.qname = sname; iq->qchase.qname_len = slen; /* This *is* a query restart, even if it is a cheap @@ -1260,6 +1341,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* if from cache, NULL, else insert 'cache IP' len=0 */ if(qstate->reply_origin) sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); + if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_SERVFAIL) + errinf(qstate, "SERVFAIL in cache"); /* it is an answer, response, to final state */ verbose(VERB_ALGO, "returning answer from cache."); iq->response = msg; @@ -1271,6 +1354,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, { if(!iq->dp) { log_err("alloc failure for forward dp"); + errinf(qstate, "malloc failure for forward zone"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->refetch_glue = 0; @@ -1290,6 +1374,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(iq->refetch_glue) { if(!iq->dp) { log_err("internal or malloc fail: no dp for refetch"); + errinf(qstate, "malloc failure, for delegation info"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } delname = iq->dp->name; @@ -1349,12 +1434,14 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, iq->qchase.qclass); if(!iq->dp) { log_err("internal error: no hints dp"); + errinf(qstate, "no hints for this class"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->dp = delegpt_copy(iq->dp, qstate->region); if(!iq->dp) { log_err("out of memory in safety belt"); + errinf(qstate, "malloc failure, in safety belt"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1398,6 +1485,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, log_nametypeclass(VERB_ALGO, "ratelimit exceeded with " "delegation point", iq->dp->name, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); + qstate->was_ratelimited = 1; + errinf(qstate, "query was ratelimited"); + errinf_dname(qstate, "for zone", iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } } @@ -1427,6 +1517,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(!iq->dp) { log_err("out of memory in " "stub/fwd fallback"); + errinf(qstate, "malloc failure, for fallback to config"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1435,6 +1526,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_ALGO, "useless dp " "but cannot go up, servfail"); delegpt_log(VERB_ALGO, iq->dp); + errinf(qstate, "no useful nameservers, " + "and cannot go up"); + errinf_dname(qstate, "for zone", iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1454,6 +1548,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, iq->dp = delegpt_copy(iq->dp, qstate->region); if(!iq->dp) { log_err("out of memory in safety belt"); + errinf(qstate, "malloc failure, in safety belt, for root"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1508,6 +1603,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_hints_stub* stub; if(!iq->dp) { log_err("internal or malloc fail: no dp for refetch"); + errinf(qstate, "malloc failure, no delegation info"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } /* Do not send queries above stub, do not set delname to dp if @@ -1798,6 +1894,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, iq->qchase.qclass, NULL)) { /* fail -- no more targets, no more hope of targets, no hope * of a response. */ + errinf(qstate, "all the configured stub or forward servers failed,"); + errinf_dname(qstate, "at zone", iq->dp->name); verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL"); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1857,6 +1955,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, int qs = 0; verbose(VERB_ALGO, "try parent-side target name"); if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) { + errinf(qstate, "could not fetch nameserver"); + errinf_dname(qstate, "at zone", iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; @@ -1868,6 +1968,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, } if(iq->depth == ie->max_dependency_depth) { verbose(VERB_QUERY, "maxdepth and need more nameservers, fail"); + errinf(qstate, "cannot fetch more nameservers because at max dependency depth"); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(iq->depth > 0 && iq->target_count && @@ -1876,6 +1977,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, dname_str(qstate->qinfo.qname, s); verbose(VERB_QUERY, "request %s has exceeded the maximum " "number of glue fetches %d", s, iq->target_count[1]); + errinf(qstate, "exceeded the maximum number of glue fetches"); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } /* mark cycle targets for parent-side lookups */ @@ -1901,9 +2003,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* Send the AAAA request. */ if(!generate_parentside_target_query(qstate, iq, id, ns->name, ns->namelen, - LDNS_RR_TYPE_AAAA, iq->qchase.qclass)) + LDNS_RR_TYPE_AAAA, iq->qchase.qclass)) { + errinf_dname(qstate, "could not generate nameserver AAAA lookup for", ns->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } ns->done_pside6 = 1; query_count++; } @@ -1911,9 +2015,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* Send the A request. */ if(!generate_parentside_target_query(qstate, iq, id, ns->name, ns->namelen, - LDNS_RR_TYPE_A, iq->qchase.qclass)) + LDNS_RR_TYPE_A, iq->qchase.qclass)) { + errinf_dname(qstate, "could not generate nameserver A lookup for", ns->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } ns->done_pside4 = 1; query_count++; } @@ -1934,6 +2040,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, iq->deleg_msg?iq->deleg_msg->rep: (iq->response?iq->response->rep:NULL)); + errinf(qstate, "all servers for this domain failed,"); + errinf_dname(qstate, "at zone", iq->dp->name); verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL"); /* fail -- no more targets, no more hope of targets, no hope * of a response. */ @@ -1967,6 +2075,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id) } /* robustcheck for internal error: we are not underneath the dp */ if(!dname_subdomain_c(iq->dsns_point, iq->dp->name)) { + errinf_dname(qstate, "for DS query parent-child nameserver search the query is not under the zone", iq->dp->name); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1987,6 +2096,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id) if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len, LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) { + errinf_dname(qstate, "for DS query parent-child nameserver search, could not generate NS lookup for", iq->dsns_point); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -2032,11 +2142,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, if(iq->referral_count > MAX_REFERRAL_COUNT) { 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); } if(iq->sent_count > 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); } @@ -2044,6 +2156,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * or another failure occurred */ if(!iq->dp) { verbose(VERB_QUERY, "Failed to get a delegation, giving up"); + errinf(qstate, "failed to get a delegation (eg. prime failure)"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } if(!ie->supports_ipv6) @@ -2203,6 +2316,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * no internet fallback */ 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); } if(iq->dp && iq->dp->auth_dp) { @@ -2228,6 +2342,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, int extra = 0; size_t naddr, nres, navail; if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) { + errinf(qstate, "could not fetch nameservers for 0x20 fallback"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; @@ -2308,6 +2423,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "missing target"); if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) { + errinf(qstate, "could not fetch nameserver"); + errinf_dname(qstate, "at zone", iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -2378,6 +2495,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, ie->num_queries_ratelimited++; lock_basic_unlock(&ie->queries_ratelimit_lock); verbose(VERB_ALGO, "query exceeded ratelimits"); + qstate->was_ratelimited = 1; + errinf_dname(qstate, "exceeded ratelimit for zone", + iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } } @@ -2542,6 +2662,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* DNAME to a subdomain loop; do not recurse */ type = RESPONSE_TYPE_ANSWER; } + } else if(type == RESPONSE_TYPE_CNAME && + iq->qchase.qtype == LDNS_RR_TYPE_CNAME && + iq->minimisation_state == MINIMISE_STATE && + query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) { + /* The minimised query for full QTYPE and hidden QTYPE can be + * classified as CNAME response type, even when the original + * QTYPE=CNAME. This should be treated as answer response type. + */ + type = RESPONSE_TYPE_ANSWER; } /* handle each of the type cases */ @@ -2690,11 +2819,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->dp = delegpt_from_message(iq->response, qstate->region); if (qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; - if(!iq->dp) + if(!iq->dp) { + errinf(qstate, "malloc failure, for delegation point"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } if(!cache_fill_missing(qstate->env, iq->qchase.qclass, - qstate->region, iq->dp)) + qstate->region, iq->dp)) { + errinf(qstate, "malloc failure, copy extra info into delegation point"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } if(iq->store_parent_NS && query_dname_compare(iq->dp->name, iq->store_parent_NS->name) == 0) iter_merge_retry_counts(iq->dp, iq->store_parent_NS); @@ -2756,8 +2889,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, } /* Process the CNAME response. */ if(!handle_cname_response(qstate, iq, iq->response, - &sname, &snamelen)) + &sname, &snamelen)) { + errinf(qstate, "malloc failure, CNAME info"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } /* cache the CNAME response under the current query */ /* NOTE : set referral=1, so that rrsets get stored but not * the partial query answer (CNAME only). */ @@ -2858,6 +2993,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->dp->name, iq->dp->namelen, qstate->qinfo.qclass)) { verbose(VERB_ALGO, "auth zone response bad, and no" " fallback possible, servfail"); + errinf_dname(qstate, "reponse is bad, no fallback, " + "for auth zone", iq->dp->name); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } verbose(VERB_ALGO, "auth zone response was bad, " @@ -2948,6 +3085,8 @@ processPrimeResponse(struct module_qstate* qstate, int id) qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_msg = iq->response; } else { + errinf(qstate, "prime response did not get an answer"); + errinf_dname(qstate, "for", qstate->qinfo.qname); qstate->return_rcode = LDNS_RCODE_SERVFAIL; qstate->return_msg = NULL; } @@ -3091,6 +3230,7 @@ processDSNSResponse(struct module_qstate* qstate, int id, foriq->dp = delegpt_from_message(qstate->return_msg, forq->region); if(!foriq->dp) { log_err("out of memory in dsns dp alloc"); + errinf(qstate, "malloc failure, in DS search"); return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */ } /* success, go query the querytargets in the new dp (and go down) */ @@ -3191,6 +3331,8 @@ processClassResponse(struct module_qstate* qstate, int id, to->rep->ttl = from->rep->ttl; if(from->rep->prefetch_ttl < to->rep->prefetch_ttl) to->rep->prefetch_ttl = from->rep->prefetch_ttl; + if(from->rep->serve_expired_ttl < to->rep->serve_expired_ttl) + to->rep->serve_expired_ttl = from->rep->serve_expired_ttl; } /* are we done? */ foriq->num_current_queries --; @@ -3229,6 +3371,8 @@ processCollectClass(struct module_qstate* qstate, int id) c, qstate, id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, (int)!(qstate->query_flags&BIT_CD))) { + errinf(qstate, "could not generate class ANY" + " lookup query"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -3275,6 +3419,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, (iq->response?iq->response->rep:NULL)); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); + errinf(qstate, "(no response found at query finish)"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -3445,6 +3590,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->caps_server = 0; iq->caps_reply = NULL; iq->caps_response = NULL; + iq->caps_minimisation_state = DONOT_MINIMISE_STATE; iq->state = QUERYTARGETS_STATE; iq->num_current_queries--; /* need fresh attempts for the 0x20 fallback, if @@ -3459,6 +3605,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, || !qstate->reply) { log_err("Bad event combined with response"); outbound_list_remove(&iq->outlist, outbound); + errinf(qstate, "module iterator received wrong internal event with a response message"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return; } @@ -3511,6 +3658,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->caps_server = 0; iq->caps_reply = NULL; iq->caps_response = NULL; + iq->caps_minimisation_state = DONOT_MINIMISE_STATE; iq->state = QUERYTARGETS_STATE; iq->num_current_queries--; verbose(VERB_DETAIL, "Capsforid: scrub failed, starting fallback with no response"); @@ -3530,15 +3678,30 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->response->rep); if(event == module_event_capsfail || iq->caps_fallback) { + if(qstate->env->cfg->qname_minimisation && + iq->minimisation_state != DONOT_MINIMISE_STATE) { + /* Skip QNAME minimisation for next query, since that + * one has to match the current query. */ + iq->minimisation_state = SKIP_MINIMISE_STATE; + } /* for fallback we care about main answer, not additionals */ /* removing that makes comparison more likely to succeed */ caps_strip_reply(iq->response->rep); + + if(iq->caps_fallback && + iq->caps_minimisation_state != iq->minimisation_state) { + /* QNAME minimisation state has changed, restart caps + * fallback. */ + iq->caps_fallback = 0; + } + if(!iq->caps_fallback) { /* start fallback */ iq->caps_fallback = 1; iq->caps_server = 0; iq->caps_reply = iq->response->rep; iq->caps_response = iq->response; + iq->caps_minimisation_state = iq->minimisation_state; iq->state = QUERYTARGETS_STATE; iq->num_current_queries--; verbose(VERB_DETAIL, "Capsforid: starting fallback"); @@ -3570,6 +3733,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_DETAIL, "Capsforid fallback: " "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, LDNS_RCODE_SERVFAIL); return; @@ -3608,6 +3772,7 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, if((event == module_event_new || event == module_event_pass) && iq == NULL) { if(!iter_new(qstate, id)) { + errinf(qstate, "malloc failure, new iterator module allocation"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return; } @@ -3625,11 +3790,13 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, } if(event == module_event_error) { verbose(VERB_ALGO, "got called with event error, giving up"); + errinf(qstate, "iterator module got the error event"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return; } log_err("bad event for iterator"); + errinf(qstate, "iterator module received wrong event"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); } diff --git a/iterator/iterator.h b/iterator/iterator.h index 67ffeb147631..57cb7c4c474e 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -371,6 +371,9 @@ struct iter_qstate { /** QNAME minimisation state, RFC7816 */ enum minimisation_state minimisation_state; + /** State for capsfail: QNAME minimisation state for comparisons. */ + enum minimisation_state caps_minimisation_state; + /** * The query info that is sent upstream. Will be a subset of qchase * when qname minimisation is enabled. |