From: Matthijs Mekking Date: Fri, 12 Jan 2024 13:11:45 +0000 (+0100) Subject: Replace rbt_findnode with qp_lookup X-Git-Tag: v9.19.22~10^2~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8572435a310ff6b677eb937afb522f227b9f1e49;p=thirdparty%2Fbind9.git Replace rbt_findnode with qp_lookup 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. --- diff --git a/lib/dns/qp-cachedb.c b/lib/dns/qp-cachedb.c index a351df0f993..8e55b7d1f2c 100644 --- a/lib/dns/qp-cachedb.c +++ b/lib/dns/qp-cachedb.c @@ -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 diff --git a/lib/dns/qp-zonedb.c b/lib/dns/qp-zonedb.c index a73820e16bc..e70a05ca280 100644 --- a/lib/dns/qp-zonedb.c +++ b/lib/dns/qp-zonedb.c @@ -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); diff --git a/lib/dns/qpdb.c b/lib/dns/qpdb.c index 113fd376f2c..f0a43b54d9b 100644 --- a/lib/dns/qpdb.c +++ b/lib/dns/qpdb.c @@ -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;