]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
remove find_deepest_zonecut() from qpcache
authorEvan Hunt <each@isc.org>
Sat, 21 Mar 2026 04:45:29 +0000 (21:45 -0700)
committerColin Vidal <colin@isc.org>
Mon, 30 Mar 2026 18:41:13 +0000 (20:41 +0200)
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
lib/dns/include/dns/db.h
lib/dns/qpcache.c
lib/ns/query.c

index 58a634f82064458749c56df7e5f83258c65d3d75..8381f59718cd74e27c9f99f083e03b98ac50cf1c 100644 (file)
@@ -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
index 8682c720595ddb9eeaebca6d34f044f5a71120be..72c735a39a84b29fa21ae567b0b765f3a5b9294f 100644 (file)
@@ -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
index 1887dddf0d21de2dc8fe8e2410f64615258cd7c3..2b6eaac8c3e0aaa4ccc718828e66427dff5e999c 100644 (file)
@@ -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;
        }
 
        /*
index f9f43b363c3f495a19c530159ef149dbc6c49365..d59d1f6f73dd76dca4858096ee0385ce602569aa 100644 (file)
@@ -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) &&