From dc6202479f00aade2ada48e72ce35d45a1062235 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 20 Mar 2026 21:45:29 -0700 Subject: [PATCH] remove find_deepest_zonecut() from qpcache because the cache no longer stores delegation (parent-side) NS rrsets, and authoritative (child-side) NS rrsets don't affect recursion, it no longer makes sense for qpcache_find() to look for NS rrsets and return DNS_R_DELEGATION. that code has been removed. the cache still does search for covering DNAME records. the check_zonecut() function has been renamed to check_dname() for clarity. related changes: - one test case has been removed from the mirror system test, because it tested the behavior of a cached delegation. - query_checkrrl() and rpz_rrset_find() have been updated so they no longer expect cache responses to have DNS_R_DELEGATION response codes. --- bin/tests/system/mirror/tests.sh | 21 ----- lib/dns/include/dns/db.h | 11 +-- lib/dns/qpcache.c | 137 ++++--------------------------- lib/ns/query.c | 4 +- 4 files changed, 25 insertions(+), 148 deletions(-) diff --git a/bin/tests/system/mirror/tests.sh b/bin/tests/system/mirror/tests.sh index 58a634f8206..8381f59718c 100644 --- a/bin/tests/system/mirror/tests.sh +++ b/bin/tests/system/mirror/tests.sh @@ -332,27 +332,6 @@ grep "foo.example.*IN.*A.*127.0.0.1" dig.out.ns3.test$n >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -n=$((n + 1)) -echo_i "checking that delegations from cache which improve mirror zone delegations are properly handled ($n)" -ret=0 -# First, issue a recursive query in order to cache an RRset which is not within -# the mirror zone's bailiwick. -$DIG $DIGOPTS @10.53.0.3 sub.example. NS >dig.out.ns3.test$n.1 2>&1 || ret=1 -# Ensure the child-side NS RRset is returned. -grep "NOERROR" dig.out.ns3.test$n.1 >/dev/null || ret=1 -grep "ANSWER: 2" dig.out.ns3.test$n.1 >/dev/null || ret=1 -grep "sub.example.*IN.*NS" dig.out.ns3.test$n.1 >/dev/null || ret=1 -# Issue a non-recursive query for something below the cached zone cut. -$DIG $DIGOPTS @10.53.0.3 +norec foo.sub.example. A >dig.out.ns3.test$n.2 2>&1 || ret=1 -# Ensure the cached NS RRset is returned in a delegation, along with the -# parent-side DS RRset. -grep "NOERROR" dig.out.ns3.test$n.2 >/dev/null || ret=1 -grep "ANSWER: 0" dig.out.ns3.test$n.2 >/dev/null || ret=1 -grep "sub.example.*IN.*NS" dig.out.ns3.test$n.2 >/dev/null || ret=1 -grep "sub.example.*IN.*DS" dig.out.ns3.test$n.2 >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - n=$((n + 1)) echo_i "checking flags set in a DNSKEY response sourced from a mirror zone ($n)" ret=0 diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 8682c720595..72c735a39a8 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -932,9 +932,8 @@ dns__db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, * a zone cut. node, foundname, * and rdataset reference the * NS RRset of the zone cut. - * If 'db' is a cache database, - * then this is the deepest known - * delegation. + * This result can only occur + * if 'db' is a zone database. * * \li #DNS_R_ZONECUT type == dns_rdatatype_any, and * the desired node is a zonecut. @@ -963,12 +962,10 @@ dns__db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, * the desired type does not. * * \li #ISC_R_NOTFOUND The desired name does not - * exist, and no delegation could - * be found. This result can only + * exist. This result can only * occur if 'db' is a cache * database. The caller should - * use its nameserver(s) of last - * resort (e.g. root hints). + * recurse for the data. * * \li #DNS_R_NCACHENXDOMAIN The desired name does not * exist. 'node' is bound to the diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 1887dddf0d2..2b6eaac8c3e 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -1364,7 +1364,7 @@ find_headers(qpcnode_t *node, qpc_search_t *search, dns_rdatatype_t type, } static isc_result_t -check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) { +check_dname(qpcnode_t *node, void *arg DNS__DB_FLARG) { qpc_search_t *search = arg; dns_slabheader_t *found = NULL, *foundsig = NULL; isc_result_t result; @@ -1404,66 +1404,6 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) { return result; } -static isc_result_t -find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node, - dns_dbnode_t **nodep, dns_name_t *foundname, - dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { - isc_result_t result = ISC_R_NOTFOUND; - qpcache_t *qpdb = NULL; - - /* - * Caller must be holding the tree lock. - */ - - qpdb = search->qpdb; - - for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { - dns_slabheader_t *found = NULL, *foundsig = NULL; - isc_rwlock_t *nlock = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - dns_qpchain_node(&search->chain, i, (void **)&node, NULL); - nlock = &qpdb->buckets[node->locknum].lock; - - NODE_RDLOCK(nlock, &nlocktype); - - /* - * Look for NS and RRSIG NS rdatasets. - */ - find_headers(node, search, dns_rdatatype_ns, &found, &foundsig); - - if (found != NULL) { - /* - * If we have to set foundname, we do it before - * anything else. - */ - if (foundname != NULL) { - dns_name_copy(&node->name, foundname); - } - result = DNS_R_DELEGATION; - if (nodep != NULL) { - qpcnode_acquire( - search->qpdb, node, nlocktype, - isc_rwlocktype_none DNS__DB_FLARG_PASS); - *nodep = (dns_dbnode_t *)node; - } - bindrdatasets(search->qpdb, node, found, foundsig, - search->now, nlocktype, - isc_rwlocktype_none, rdataset, - sigrdataset DNS__DB_FLARG_PASS); - } - - NODE_UNLOCK(nlock, &nlocktype); - - if (found != NULL) { - break; - } - } - - return result; -} - /* * Look for a potentially covering NSEC in the cache where `name` * is known not to exist. This uses the auxiliary NSEC tree to find @@ -1594,14 +1534,13 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool cname_ok = true; bool found_noqname = false; bool all_negative = true; - bool empty_node; + bool empty_node = true; isc_rwlock_t *nlock = NULL; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; dns_slabheader_t *found = NULL, *foundsig = NULL; - dns_slabheader_t *nsheader = NULL, *nssig = NULL; dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL; - dns_typepair_t typepair; + dns_typepair_t typepair = DNS_TYPEPAIR(type); if (type == dns_rdatatype_none) { /* We can't search negative cache directly */ @@ -1626,8 +1565,8 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, } /* - * Check the QP chain to see if there's a node above us with a - * active DNAME or NS rdatasets. + * Check the QP chain to see if there's a node above us with an + * active DNAME rdataset. * * We're only interested in nodes above QNAME, so if the result * was success, then we skip the last item in the chain. @@ -1638,14 +1577,14 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, } for (unsigned int i = 0; i < len; i++) { - isc_result_t zcresult; + isc_result_t tresult; qpcnode_t *encloser = NULL; dns_qpchain_node(&search.chain, i, (void **)&encloser, NULL); - zcresult = check_zonecut(encloser, - (void *)&search DNS__DB_FLARG_PASS); - if (zcresult != DNS_R_CONTINUE) { + tresult = check_dname(encloser, + (void *)&search DNS__DB_FLARG_PASS); + if (tresult != DNS_R_CONTINUE) { result = DNS_R_PARTIALMATCH; search.chain.len = i - 1; node = encloser; @@ -1678,10 +1617,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, tlocktype DNS__DB_FLARG_PASS); goto tree_exit; } else { - find_ns: - result = find_deepest_zonecut( - &search, node, nodep, foundname, rdataset, - sigrdataset DNS__DB_FLARG_PASS); + result = ISC_R_NOTFOUND; goto tree_exit; } } else if (result != ISC_R_SUCCESS) { @@ -1705,19 +1641,6 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, nlock = &search.qpdb->buckets[node->locknum].lock; NODE_RDLOCK(nlock, &nlocktype); - /* - * These pointers need to be reset here in case we did - * 'goto find_ns' from somewhere below. - */ - found = NULL; - foundsig = NULL; - typepair = DNS_TYPEPAIR(type); - nsheader = NULL; - nsecheader = NULL; - nssig = NULL; - nsecsig = NULL; - empty_node = true; - DNS_SLABTOP_FOREACH(top, node->data) { dns_slabheader_t *header = NULL, *sigheader = NULL; if (DNS_TYPEPAIR_TYPE(top->typepair) == dns_rdatatype_rrsig) { @@ -1799,12 +1722,6 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, } break; - case dns_rdatatype_ns: - case DNS_SIGTYPEPAIR(dns_rdatatype_ns): - nsheader = header; - nssig = sigheader; - break; - case dns_rdatatype_nsec: case DNS_SIGTYPEPAIR(dns_rdatatype_nsec): nsecheader = header; @@ -1839,7 +1756,9 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, goto tree_exit; } } - goto find_ns; + + result = ISC_R_NOTFOUND; + goto tree_exit; } /* @@ -1874,34 +1793,14 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, result = find_coveringnsec( &search, name, nodep, foundname, rdataset, sigrdataset DNS__DB_FLARG_PASS); - if (result == DNS_R_COVERINGNSEC) { - goto tree_exit; - } - goto find_ns; - } - - /* - * If there is an NS rdataset at this node, then this is the - * deepest zone cut. - */ - if (nsheader != NULL) { - if (nodep != NULL) { - qpcnode_acquire(search.qpdb, node, nlocktype, - tlocktype DNS__DB_FLARG_PASS); - *nodep = (dns_dbnode_t *)node; + if (result != DNS_R_COVERINGNSEC) { + result = ISC_R_NOTFOUND; } - bindrdatasets(search.qpdb, node, nsheader, nssig, - search.now, nlocktype, tlocktype, - rdataset, sigrdataset DNS__DB_FLARG_PASS); - result = DNS_R_DELEGATION; - goto node_exit; + goto tree_exit; } - /* - * Go find the deepest zone cut. - */ - NODE_UNLOCK(nlock, &nlocktype); - goto find_ns; + result = ISC_R_NOTFOUND; + goto node_exit; } /* diff --git a/lib/ns/query.c b/lib/ns/query.c index f9f43b363c3..d59d1f6f73d 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -3146,6 +3146,8 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, if (result == ISC_R_NOTFOUND) { result = DNS_R_DELEGATION; } + } else if (result == ISC_R_NOTFOUND && !is_zone) { + result = DNS_R_DELEGATION; } rpz_clean(NULL, dbp, &node, NULL); if (result == DNS_R_DELEGATION) { @@ -6815,7 +6817,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) && ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) || (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) && - !(result == DNS_R_DELEGATION && !qctx->is_zone && + !(result == ISC_R_NOTFOUND && !qctx->is_zone && RECURSIONOK(qctx->client)) && (qctx->client->query.rpz_st == NULL || (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) && -- 2.47.3