]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Replace rbt_findnode with qp_lookup
authorMatthijs Mekking <matthijs@isc.org>
Fri, 12 Jan 2024 13:11:45 +0000 (14:11 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 6 Mar 2024 08:57:24 +0000 (09:57 +0100)
All dns_qp_lookup() calls assume it is okay to find empty data, so
we don't need to do anything special for the DNS_RBTFIND_EMPTYDATA.

You can pass a callback function to dns_rbt_findnode(), something that
qp does not support. Instead, call the function afterwards. This has
the drawback that we do more lookup work if there was a zonecut.

With dns_qp_lookup() we also don't pass any options. In this case,
when DNS_RBTFIND_NOEXACT was set, we adapt the result after the lookup.

lib/dns/qp-cachedb.c
lib/dns/qp-zonedb.c
lib/dns/qpdb.c

index a351df0f9931932eebc4381a4736a5b6f1be6793..8e55b7d1f2c68bc3e32380cc055c58b794c5ce72 100644 (file)
@@ -430,8 +430,7 @@ check_stale_header(dns_rbtnode_t *node, dns_slabheader_t *header,
 }
 
 static isc_result_t
-cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name,
-                      void *arg DNS__DB_FLARG) {
+check_zonecut(dns_rbtnode_t *node, void *arg DNS__DB_FLARG) {
        qpdb_search_t *search = arg;
        dns_slabheader_t *header = NULL;
        dns_slabheader_t *header_prev = NULL, *header_next = NULL;
@@ -442,11 +441,6 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name,
 
        REQUIRE(search->zonecut == NULL);
 
-       /*
-        * Keep compiler silent.
-        */
-       UNUSED(name);
-
        lock = &(search->qpdb->node_locks[node->locknum].lock);
        NODE_RDLOCK(lock, &nlocktype);
 
@@ -668,8 +662,8 @@ find_coveringnsec(qpdb_search_t *search, const dns_name_t *name,
         */
        dns_rbtnodechain_init(&chain);
        target = dns_fixedname_initname(&ftarget);
-       result = dns_rbt_findnode(search->qpdb->nsec, name, target, &node,
-                                 &chain, DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+       result = dns_qp_lookup(search->qpdb->nsec, name, target, NULL, &chain,
+                              (void **)&node, NULL);
        if (result != DNS_R_PARTIALMATCH) {
                dns_rbtnodechain_reset(&chain);
                return (ISC_R_NOTFOUND);
@@ -701,8 +695,8 @@ find_coveringnsec(qpdb_search_t *search, const dns_name_t *name,
         * Lookup the predecessor in the main tree.
         */
        node = NULL;
-       result = dns_rbt_findnode(search->qpdb->tree, target, fname, &node,
-                                 NULL, DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+       result = dns_qp_lookup(search->qpdb->tree, target, fname, NULL, NULL,
+                              (void **)&node, NULL);
        if (result != ISC_R_SUCCESS) {
                return (ISC_R_NOTFOUND);
        }
@@ -801,18 +795,46 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
        TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
 
        /*
-        * Search down from the root of the tree.  If, while going down, we
-        * encounter a callback node, cache_zonecut_callback() will search the
-        * rdatasets at the zone cut for a DNAME rdataset.
+        * Search down from the root of the tree.
         */
-       result = dns_rbt_findnode(search.qpdb->tree, name, foundname, &node,
-                                 &search.chain, DNS_RBTFIND_EMPTYDATA,
-                                 cache_zonecut_callback, &search);
+       result = dns_qp_lookup(search.qpdb->tree, name, foundname, NULL,
+                              &search.chain, (void **)&node, NULL);
+
+       /*
+        * Check the QP chain to see if there's a node above us with a
+        * active DNAME or NS rdatasets.
+        *
+        * We're only interested in nodes above QNAME, so if the result
+        * was success, then we skip the last item in the chain.
+        */
+       unsigned int len = dns_qpchain_length(&search.chain);
+       if (result == ISC_R_SUCCESS) {
+               len--;
+       }
+
+       for (unsigned int i = 0; i < len; i++) {
+               isc_result_t zcresult;
+               dns_rbtnode_t *encloser = NULL;
+
+               dns_qpchain_node(&search.chain, i, NULL, (void **)&encloser,
+                                NULL);
+
+               if (encloser->find_callback) {
+                       zcresult = check_zonecut(
+                               encloser, (void *)&search DNS__DB_FLARG_PASS);
+                       if (zcresult != DNS_R_CONTINUE) {
+                               result = DNS_R_PARTIALMATCH;
+                               search.chain.len = i - 1;
+                               node = encloser;
+                               break;
+                       }
+               }
+       }
 
        if (result == DNS_R_PARTIALMATCH) {
                /*
-                * If dns_rbt_findnode discovered a covering DNAME skip
-                * looking for a covering NSEC.
+                * If we discovered a covering DNAME skip looking for a covering
+                * NSEC.
                 */
                if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
                    (search.zonecut_header == NULL ||
@@ -1190,7 +1212,6 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
        dns_slabheader_t *header = NULL;
        dns_slabheader_t *header_prev = NULL, *header_next = NULL;
        dns_slabheader_t *found = NULL, *foundsig = NULL;
-       unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
        isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
        isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
        bool dcnull = (dcname == NULL);
@@ -1214,17 +1235,25 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
                dcname = foundname;
        }
 
-       if ((options & DNS_DBFIND_NOEXACT) != 0) {
-               rbtoptions |= DNS_RBTFIND_NOEXACT;
-       }
-
        TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
 
        /*
         * Search down from the root of the tree.
         */
-       result = dns_rbt_findnode(search.qpdb->tree, name, dcname, &node,
-                                 &search.chain, rbtoptions, NULL, &search);
+       result = dns_qp_lookup(search.qpdb->tree, name, dcname, NULL,
+                              &search.chain, (void **)&node, NULL);
+       if ((options & DNS_DBFIND_NOEXACT) != 0 && result == ISC_R_SUCCESS) {
+               int len = dns_qpchain_length(&search.chain);
+               if (len >= 2) {
+                       node = NULL;
+                       dns_qpchain_node(&search.chain, len - 2, NULL,
+                                        (void **)&node, NULL);
+                       search.chain.len = len - 1;
+                       result = DNS_R_PARTIALMATCH;
+               } else {
+                       result = ISC_R_NOTFOUND;
+               }
+       }
 
        if (result == DNS_R_PARTIALMATCH) {
                result = find_deepest_zonecut(&search, node, nodep, foundname,
@@ -1250,7 +1279,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
                                       &header_prev))
                {
                        /*
-                        * The function dns_rbt_findnode found us the a matching
+                        * The function dns_qp_lookup found us a matching
                         * node for 'name' and stored the result in 'dcname'.
                         * This is the deepest known zonecut in our database.
                         * However, this node may be stale and if serve-stale
index a73820e16bc4e8108958d30f72278e57167c0977..e70a05ca280860744e002cf4168dafb96aba7f01 100644 (file)
@@ -103,8 +103,7 @@ findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
 }
 
 static isc_result_t
-zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name,
-                     void *arg DNS__DB_FLARG) {
+check_zonecut(dns_rbtnode_t *node, void *arg DNS__DB_FLARG) {
        qpdb_search_t *search = arg;
        dns_slabheader_t *header = NULL, *header_next = NULL;
        dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
@@ -227,7 +226,7 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name,
                         * is, we need to remember the node name.
                         */
                        zcname = dns_fixedname_name(&search->zonecut_name);
-                       dns_name_copy(name, zcname);
+                       dns_name_copy(node->name, zcname);
                        search->copy_name = true;
                }
        } else {
@@ -472,15 +471,11 @@ static isc_result_t
 find_wildcard(qpdb_search_t *search, dns_rbtnode_t **nodep,
              const dns_name_t *qname) {
        unsigned int i, j;
-       dns_rbtnode_t *node = NULL, *level_node = NULL, *wnode = NULL;
+       dns_rbtnode_t *node = NULL, *level_node = NULL;
        dns_slabheader_t *header = NULL;
        isc_result_t result = ISC_R_NOTFOUND;
-       dns_name_t name;
-       dns_name_t *wname = NULL;
-       dns_fixedname_t fwname;
        dns_qpdb_t *qpdb = NULL;
        bool done, wild, active;
-       dns_rbtnodechain_t wchain;
 
        /*
         * Caller must be holding the tree lock and MUST NOT be holding
@@ -536,6 +531,11 @@ find_wildcard(qpdb_search_t *search, dns_rbtnode_t **nodep,
                NODE_UNLOCK(lock, &nlocktype);
 
                if (wild) {
+                       dns_name_t *wname = NULL;
+                       dns_fixedname_t fwname;
+                       dns_rbtnode_t *wnode = NULL;
+                       dns_qpiter_t wchain;
+
                        /*
                         * Construct the wildcard name for this level.
                         */
@@ -559,9 +559,9 @@ find_wildcard(qpdb_search_t *search, dns_rbtnode_t **nodep,
 
                        wnode = NULL;
                        dns_rbtnodechain_init(&wchain);
-                       result = dns_rbt_findnode(
-                               qpdb->tree, wname, NULL, &wnode, &wchain,
-                               DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+
+                       result = dns_qp_lookup(qpdb->tree, wname, NULL, NULL,
+                                              &wchain, (void **)&wnode, NULL);
                        if (result == ISC_R_SUCCESS) {
                                /*
                                 * We have found the wildcard node.  If it
@@ -709,9 +709,9 @@ previous_closest_nsec(dns_rdatatype_t type, qpdb_search_t *search,
                                return (result);
                        }
                        nsecnode = NULL;
-                       result = dns_rbt_findnode(
-                               search->qpdb->nsec, target, NULL, &nsecnode,
-                               nsecchain, DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+                       result = dns_qp_lookup(search->qpdb->nsec, name, NULL,
+                                              NULL, nsecchain,
+                                              (void **)&nsecnode, NULL);
                        if (result == ISC_R_SUCCESS) {
                                /*
                                 * Since this was the first loop, finding the
@@ -728,6 +728,7 @@ previous_closest_nsec(dns_rdatatype_t type, qpdb_search_t *search,
                        } else if (result == ISC_R_NOTFOUND ||
                                   result == DNS_R_PARTIALMATCH)
                        {
+                               /* The iterator is already where we want it */
                                result = dns_rbtnodechain_current(
                                        nsecchain, name, origin, NULL);
                                if (result == ISC_R_NOTFOUND) {
@@ -751,18 +752,10 @@ previous_closest_nsec(dns_rdatatype_t type, qpdb_search_t *search,
                        return (result);
                }
 
-               /*
-                * Construct the name to seek in the main tree.
-                */
-               result = dns_name_concatenate(name, origin, target, NULL);
-               if (result != ISC_R_SUCCESS) {
-                       return (result);
-               }
-
                *nodep = NULL;
-               result = dns_rbt_findnode(search->qpdb->tree, target, NULL,
-                                         nodep, &search->chain,
-                                         DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+               result = dns_qp_lookup(search->qpdb->tree, name, NULL,
+                                      &search->iter, &search->chain,
+                                      (void **)nodep, NULL);
                if (result == ISC_R_SUCCESS) {
                        return (result);
                }
@@ -1032,15 +1025,43 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
        TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
 
        /*
-        * Search down from the root of the tree.  If, while going down, we
-        * encounter a callback node, zone_zonecut_callback() will search the
-        * rdatasets at the zone cut for active DNAME or NS rdatasets.
+        * Search down from the root of the tree.
         */
        tree = (options & DNS_DBFIND_FORCENSEC3) != 0 ? search.qpdb->nsec3
                                                      : search.qpdb->tree;
-       result = dns_rbt_findnode(tree, name, foundname, &node, &search.chain,
-                                 DNS_RBTFIND_EMPTYDATA, zone_zonecut_callback,
-                                 &search);
+       result = dns_qp_lookup(tree, name, foundname, &search.iter,
+                              &search.chain, (void **)&node, NULL);
+
+       /*
+        * Check the QP chain to see if there's a node above us with a
+        * active DNAME or NS rdatasets.
+        *
+        * We're only interested in nodes above QNAME, so if the result
+        * was success, then we skip the last item in the chain.
+        */
+       unsigned int len = dns_qpchain_length(&search.chain);
+       if (result == ISC_R_SUCCESS) {
+               len--;
+       }
+
+       for (unsigned int i = 0; i < len; i++) {
+               isc_result_t zcresult;
+               dns_rbtnode_t *encloser = NULL;
+
+               dns_qpchain_node(&search.chain, i, NULL, (void **)&encloser,
+                                NULL);
+
+               if (encloser->find_callback) {
+                       zcresult = check_zonecut(
+                               encloser, (void *)&search DNS__DB_FLARG_PASS);
+                       if (zcresult != DNS_R_CONTINUE) {
+                               result = DNS_R_PARTIALMATCH;
+                               search.chain.len = i - 1;
+                               node = encloser;
+                               break;
+                       }
+               }
+       }
 
        if (result == DNS_R_PARTIALMATCH) {
        partial_match:
@@ -1108,6 +1129,9 @@ found:
         * have matched a wildcard.
         */
 
+       lock = &search.qpdb->node_locks[node->locknum].lock;
+       NODE_RDLOCK(lock, &nlocktype);
+
        if (search.zonecut != NULL) {
                /*
                 * If we're beneath a zone cut, we don't want to look for
@@ -1148,9 +1172,6 @@ found:
         * We now go looking for rdata...
         */
 
-       lock = &search.qpdb->node_locks[node->locknum].lock;
-       NODE_RDLOCK(lock, &nlocktype);
-
        found = NULL;
        foundsig = NULL;
        sigtype = DNS_SIGTYPE(type);
index 113fd376f2cee41dcb8c312574e5d3ac27030bd7..f0a43b54d9be05d3979d0ff4e75451bb015e8bed 100644 (file)
@@ -1977,8 +1977,8 @@ dns__qpdb_findnodeintree(dns_qpdb_t *qpdb, dns_qp_t *tree,
 
        dns_name_init(&nodename, NULL);
        TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
-       result = dns_rbt_findnode(tree, name, NULL, &node, NULL,
-                                 DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+       result = dns_qp_lookup(tree, name, NULL, NULL, NULL, (void **)&node,
+                              NULL);
        if (result != ISC_R_SUCCESS) {
                if (!create) {
                        if (result == DNS_R_PARTIALMATCH) {
@@ -4412,30 +4412,30 @@ dbiterator_seek(dns_dbiterator_t *iterator,
        switch (qpdbiter->nsec3mode) {
        case nsec3only:
                qpdbiter->current = &qpdbiter->nsec3chain;
-               result = dns_rbt_findnode(qpdb->nsec3, name, NULL,
-                                         &qpdbiter->node, qpdbiter->current,
-                                         DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+               result = dns_qp_lookup(qpdb->nsec3, name, NULL,
+                                      qpdbiter->current, NULL,
+                                      (void **)&qpdbiter->node, NULL);
                break;
        case nonsec3:
                qpdbiter->current = &qpdbiter->chain;
-               result = dns_rbt_findnode(qpdb->tree, name, NULL,
-                                         &qpdbiter->node, qpdbiter->current,
-                                         DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+               result = dns_qp_lookup(qpdb->tree, name, NULL,
+                                      qpdbiter->current, NULL,
+                                      (void **)&qpdbiter->node, NULL);
                break;
        case full:
                /*
-                * Stay on main chain if not found on either chain.
+                * Stay on main chain if not found on
+                * either chain.
                 */
                qpdbiter->current = &qpdbiter->chain;
-               result = dns_rbt_findnode(qpdb->tree, name, NULL,
-                                         &qpdbiter->node, qpdbiter->current,
-                                         DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+               result = dns_qp_lookup(qpdb->tree, name, NULL,
+                                      qpdbiter->current, NULL,
+                                      (void **)&qpdbiter->node, NULL);
                if (result == DNS_R_PARTIALMATCH) {
                        dns_rbtnode_t *node = NULL;
-                       tresult = dns_rbt_findnode(qpdb->nsec3, name, NULL,
-                                                  &node, &qpdbiter->nsec3chain,
-                                                  DNS_RBTFIND_EMPTYDATA, NULL,
-                                                  NULL);
+                       tresult = dns_qp_lookup(qpdb->nsec3, name, NULL,
+                                               &qpdbiter->nsec3chain, NULL,
+                                               (void **)&node, NULL);
                        if (tresult == ISC_R_SUCCESS) {
                                qpdbiter->node = node;
                                qpdbiter->current = &qpdbiter->nsec3chain;