From: W.C.A. Wijngaards Date: Tue, 13 Apr 2021 11:52:57 +0000 (+0200) Subject: - Fix that nxdomain synthesis does not happen above the stub or X-Git-Tag: release-1.13.2rc1~196^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55ba863440dc5b1266b79f26ed92bbbdde5a2ebb;p=thirdparty%2Funbound.git - Fix that nxdomain synthesis does not happen above the stub or forward definition. --- diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index e948a6b0d..af4ffe5f2 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -617,12 +617,18 @@ cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie) static int cachedb_intcache_lookup(struct module_qstate* qstate) { + uint8_t* dpname=NULL; + size_t dpnamelen=0; struct dns_msg* msg; + if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, + &dpname, &dpnamelen)) + return 0; /* no cache for these queries */ msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname, qstate->qinfo.qname_len, qstate->qinfo.qtype, qstate->qinfo.qclass, qstate->query_flags, qstate->region, qstate->env->scratch, - 1 /* no partial messages with only a CNAME */ + 1, /* no partial messages with only a CNAME */ + dpname, dpnamelen ); if(!msg && qstate->env->neg_cache && iter_qname_indicates_dnssec(qstate->env, &qstate->qinfo)) { diff --git a/doc/Changelog b/doc/Changelog index c62b48893..1f61b19bb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +13 April 2021: Wouter + - Fix that nxdomain synthesis does not happen above the stub or + forward definition. + 12 April 2021: George - Fix (increase) verbosity level for iterator error log in processQueryTargets(). diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c index 6c8589aba..ade40c66e 100644 --- a/edns-subnet/subnetmod.c +++ b/edns-subnet/subnetmod.c @@ -150,7 +150,7 @@ int ecs_whitelist_check(struct query_info* qinfo, /* Cache by default, might be disabled after parsing EDNS option * received from nameserver. */ - if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo)) { + if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)) { qstate->no_cache_store = 0; } diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 94fa18f63..adc611f73 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -1391,7 +1391,8 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp) } int -iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf) +iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, + uint8_t** retdpname, size_t* retdpnamelen) { struct iter_hints_stub *stub; struct delegpt *dp; @@ -1420,6 +1421,10 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf) dname_str(stub->dp->name, dpname); verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); } + if(retdpname) { + *retdpname = stub->dp->name; + *retdpnamelen = stub->dp->namelen; + } return (stub->dp->no_cache); } @@ -1432,8 +1437,16 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf) dname_str(dp->name, dpname); verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); } + if(retdpname) { + *retdpname = dp->name; + *retdpnamelen = dp->namelen; + } return (dp->no_cache); } + if(retdpname) { + *retdpname = NULL; + *retdpnamelen = 0; + } return 0; } diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 7be79cf4a..509d2921e 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -382,10 +382,15 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp); * Lookup if no_cache is set in stub or fwd. * @param qstate: query state with env with hints and fwds. * @param qinf: query name to lookup for. + * @param retdpname: returns NULL or the deepest enclosing name of fwd or stub. + * This is the name under which the closest lookup is going to happen. + * Used for NXDOMAIN checks, above that it is an nxdomain from a + * different server and zone. You can pass NULL to not get it. + * @param retdpnamelen: returns the length of the dpname. * @return true if no_cache is set in stub or fwd. */ int iter_stub_fwd_no_cache(struct module_qstate *qstate, - struct query_info *qinf); + struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen); /** * Set support for IP4 and IP6 depending on outgoing interfaces diff --git a/iterator/iterator.c b/iterator/iterator.c index 83ded0808..0f662304d 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1228,8 +1228,8 @@ static int processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_env* ie, int id) { - uint8_t* delname; - size_t delnamelen; + uint8_t* delname, *dpname=NULL; + size_t delnamelen, dpnamelen=0; struct dns_msg* msg = NULL; log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo); @@ -1283,7 +1283,7 @@ 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 (iter_stub_fwd_no_cache(qstate, &iq->qchase)) { + if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen)) { /* Asked to not query cache. */ verbose(VERB_ALGO, "no-cache set, going to the network"); qstate->no_cache_lookup = 1; @@ -1298,7 +1298,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, msg = dns_cache_lookup(qstate->env, iq->qchase.qname, iq->qchase.qname_len, iq->qchase.qtype, iq->qchase.qclass, qstate->query_flags, - qstate->region, qstate->env->scratch, 0); + qstate->region, qstate->env->scratch, 0, dpname, + dpnamelen); if(!msg && qstate->env->neg_cache && iter_qname_indicates_dnssec(qstate->env, &iq->qchase)) { /* lookup in negative cache; may result in @@ -2288,7 +2289,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->qinfo_out.qname, iq->qinfo_out.qname_len, iq->qinfo_out.qtype, iq->qinfo_out.qclass, qstate->query_flags, qstate->region, - qstate->env->scratch, 0); + qstate->env->scratch, 0, iq->dp->name, + iq->dp->namelen); if(msg && FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NOERROR) /* no need to send query if it is already diff --git a/services/cache/dns.c b/services/cache/dns.c index f3149b614..5b64fe475 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -801,7 +801,7 @@ struct dns_msg* dns_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, struct regional* region, struct regional* scratch, - int no_partial) + int no_partial, uint8_t* dpname, size_t dpnamelen) { struct lruhash_entry* e; struct query_info k; @@ -923,6 +923,9 @@ dns_cache_lookup(struct module_env* env, * the same. We search upwards for NXDOMAINs. */ if(env->cfg->harden_below_nxdomain) { while(!dname_is_root(k.qname)) { + if(dpname && dpnamelen + && !dname_subdomain_c(k.qname, dpname)) + break; /* no synth nxdomain above the stub */ dname_remove_label(&k.qname, &k.qname_len); h = query_info_hash(&k, flags); e = slabhash_lookup(env->msg_cache, h, &k, 0); diff --git a/services/cache/dns.h b/services/cache/dns.h index f1b77fb36..bece83702 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -164,6 +164,8 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q, * @param scratch: where to allocate temporary data. * @param no_partial: if true, only complete messages and not a partial * one (with only the start of the CNAME chain and not the rest). + * @param dpname: if not NULL, do not return NXDOMAIN above this name. + * @param dpnamelen: length of dpname. * @return new response message (alloced in region, rrsets do not have IDs). * or NULL on error or if not found in cache. * TTLs are made relative to the current time. @@ -171,7 +173,7 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q, struct dns_msg* dns_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, struct regional* region, struct regional* scratch, - int no_partial); + int no_partial, uint8_t* dpname, size_t dpnamelen); /** * find and add A and AAAA records for missing nameservers in delegpt