From ab084d8c4f195d90f8d6e8f6949e0c20c477bfc9 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 6 Mar 2024 15:04:20 -0800 Subject: [PATCH] remove qp-zonedb.c and associated code now that "qpzone" databases are available for use in zones, we no longer need to retain the zone semantics in the "qp" database. all zone-specific code has been removed from QPDB, and "configure --with-zonedb" once again takes two values, rbt and qp. some database API methods that are never used with a cache have been removed from qpdb.c and qp-cachedb.c; these include newversion, closeversion, subtractrdataset, and nodefullname. --- bin/tests/system/dyndb/driver/db.c | 4 +- configure.ac | 8 +- lib/dns/Makefile.am | 1 - lib/dns/qp-cachedb.c | 6 - lib/dns/qp-zonedb.c | 2489 ---------------------------- lib/dns/qpdb.c | 1881 ++------------------- lib/dns/qpdb_p.h | 106 +- tests/dns/qpdb_test.c | 175 -- 8 files changed, 138 insertions(+), 4532 deletions(-) delete mode 100644 lib/dns/qp-zonedb.c diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c index 9fa587d16d..90ddac13d1 100644 --- a/bin/tests/system/dyndb/driver/db.c +++ b/bin/tests/system/dyndb/driver/db.c @@ -621,8 +621,8 @@ create_db(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, /* Translate instance name to instance pointer. */ sampledb->inst = driverarg; - /* Create internal instance of RBT DB implementation from BIND. */ - CHECK(dns_db_create(mctx, "qp", origin, dns_dbtype_zone, + /* Create internal instance of DB implementation from BIND. */ + CHECK(dns_db_create(mctx, ZONEDB_DEFAULT, origin, dns_dbtype_zone, dns_rdataclass_in, 0, NULL, &sampledb->rbtdb)); /* Create fake SOA, NS, and A records to make database loadable. */ diff --git a/configure.ac b/configure.ac index ec2f505122..070bccf102 100644 --- a/configure.ac +++ b/configure.ac @@ -1570,9 +1570,8 @@ AS_IF([test -z "$DTRACE"], AC_SUBST([DTRACE]) # -# Which should be the default zone database, RBTDB, QPDB (based on dns_qp), -# or QPZONE (based on dns_qpmulti)? -# [pairwise: --with-zonedb=qp, --with-zonedb=qpzone, --with-zonedb=rbt] +# Which should be the default zone database, RBTDB or QPZONE? +# [pairwise: --with-zonedb=qp, --with-zonedb=rbt] # AC_ARG_WITH([zonedb], [AS_HELP_STRING([--with-zonedb=detect],[specify default zone database type (default is "qpzone")])], @@ -1580,8 +1579,7 @@ AC_ARG_WITH([zonedb], zonedb="qpzone" AS_CASE([$with_zonedb], [RBT*|rbt*],[zonedb="rbt"], - [QP|qp],[zonedb="qp"], - [QPZ*|qpz*],[], + [QP|qp],[], [AC_MSG_ERROR([Unknown zone database type])] ) AC_DEFINE_UNQUOTED([ZONEDB_DEFAULT], ["$zonedb"], [Default zone database type]) diff --git a/lib/dns/Makefile.am b/lib/dns/Makefile.am index 0cef1256cb..ca4e06b3e1 100644 --- a/lib/dns/Makefile.am +++ b/lib/dns/Makefile.am @@ -224,7 +224,6 @@ libdns_la_SOURCES = \ rbtdb.c \ rbtdb_p.h \ qp-cachedb.c \ - qp-zonedb.c \ qpdb_p.h \ qpdb.c \ rcode.c \ diff --git a/lib/dns/qp-cachedb.c b/lib/dns/qp-cachedb.c index cc0562bb7c..2c9b7bd1d5 100644 --- a/lib/dns/qp-cachedb.c +++ b/lib/dns/qp-cachedb.c @@ -1521,10 +1521,6 @@ expiredata(dns_db_t *db, dns_dbnode_t *node, void *data) { dns_dbmethods_t dns__qpdb_cachemethods = { .destroy = dns__qpdb_destroy, - .currentversion = dns__qpdb_currentversion, - .newversion = dns__qpdb_newversion, - .attachversion = dns__qpdb_attachversion, - .closeversion = dns__qpdb_closeversion, .findnode = dns__qpdb_findnode, .find = cache_find, .findzonecut = cache_findzonecut, @@ -1534,7 +1530,6 @@ dns_dbmethods_t dns__qpdb_cachemethods = { .findrdataset = cache_findrdataset, .allrdatasets = dns__qpdb_allrdatasets, .addrdataset = dns__qpdb_addrdataset, - .subtractrdataset = dns__qpdb_subtractrdataset, .deleterdataset = dns__qpdb_deleterdataset, .nodecount = dns__qpdb_nodecount, .setloop = dns__qpdb_setloop, @@ -1549,7 +1544,6 @@ dns_dbmethods_t dns__qpdb_cachemethods = { .unlocknode = dns__qpdb_unlocknode, .expiredata = expiredata, .deletedata = dns__qpdb_deletedata, - .nodefullname = dns__qpdb_nodefullname, }; /* diff --git a/lib/dns/qp-zonedb.c b/lib/dns/qp-zonedb.c deleted file mode 100644 index 2c6b9cac37..0000000000 --- a/lib/dns/qp-zonedb.c +++ /dev/null @@ -1,2489 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * SPDX-License-Identifier: MPL-2.0 - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -/*! \file */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "db_p.h" -#include "qpdb_p.h" - -#define CHECK(op) \ - do { \ - result = (op); \ - if (result != ISC_R_SUCCESS) \ - goto failure; \ - } while (0) - -#define EXISTS(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_NONEXISTENT) == 0) -#define NONEXISTENT(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_NONEXISTENT) != 0) -#define IGNORE(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_IGNORE) != 0) -#define RESIGN(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_RESIGN) != 0) -#define ANCIENT(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_ANCIENT) != 0) - -#define QPDB_ATTR_LOADED 0x01 -#define QPDB_ATTR_LOADING 0x02 - -static isc_result_t -findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, - dns_dbnode_t **nodep DNS__DB_FLARG) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - - REQUIRE(VALID_QPDB(qpdb)); - - return (dns__qpdb_findnodeintree(qpdb, qpdb->nsec3, name, create, - nodep DNS__DB_FLARG_PASS)); -} - -static isc_result_t -check_zonecut(dns_qpdata_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; - dns_slabheader_t *ns_header = NULL; - dns_slabheader_t *found = NULL; - isc_result_t result = DNS_R_CONTINUE; - dns_qpdata_t *onode = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - /* - * We only want to remember the topmost zone cut, since it's the one - * that counts, so we'll just continue if we've already found a - * zonecut. - */ - if (search->zonecut != NULL) { - return (result); - } - - onode = search->qpdb->origin_node; - - NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - - /* - * Look for an NS or DNAME rdataset active in our version. - */ - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (header->type == dns_rdatatype_ns || - header->type == dns_rdatatype_dname || - header->type == DNS_SIGTYPE(dns_rdatatype_dname)) - { - do { - if (header->serial <= search->serial && - !IGNORE(header)) - { - /* - * Is this a "this rdataset doesn't - * exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - if (header->type == dns_rdatatype_dname) { - dname_header = header; - } else if (header->type == - DNS_SIGTYPE(dns_rdatatype_dname)) - { - sigdname_header = header; - } else if (node != onode || - IS_STUB(search->qpdb)) - { - /* - * We've found an NS rdataset that - * isn't at the origin node. We check - * that they're not at the origin node, - * because otherwise we'd erroneously - * treat the zone top as if it were - * a delegation. - */ - ns_header = header; - } - } - } - } - - /* - * Did we find anything? - */ - if (!IS_STUB(search->qpdb) && ns_header != NULL) { - /* - * Note that NS has precedence over DNAME if both exist - * in a zone. Otherwise DNAME take precedence over NS. - */ - found = ns_header; - search->zonecut_sigheader = NULL; - } else if (dname_header != NULL) { - found = dname_header; - search->zonecut_sigheader = sigdname_header; - } else if (ns_header != NULL) { - found = ns_header; - search->zonecut_sigheader = NULL; - } - - if (found != NULL) { - /* - * We increment the reference count on node to ensure that - * search->zonecut_header will still be valid later. - */ - dns__qpdb_newref(search->qpdb, node, - isc_rwlocktype_read DNS__DB_FLARG_PASS); - search->zonecut = node; - search->zonecut_header = found; - search->need_cleanup = true; - /* - * Since we've found a zonecut, anything beneath it is - * glue and is not subject to wildcard matching, so we - * may clear search->wild. - */ - search->wild = false; - if ((search->options & DNS_DBFIND_GLUEOK) == 0) { - /* - * If the caller does not want to find glue, then - * this is the best answer and the search should - * stop now. - */ - result = DNS_R_PARTIALMATCH; - } else { - dns_name_t *zcname = NULL; - - /* - * The search will continue beneath the zone cut. - * This may or may not be the best match. In case it - * is, we need to remember the node name. - */ - zcname = dns_fixedname_name(&search->zonecut_name); - dns_name_copy(node->name, zcname); - search->copy_name = true; - } - } else { - /* - * There is no zonecut at this node which is active in this - * version. - * - * If this is a "wild" node and the caller hasn't disabled - * wildcard matching, remember that we've seen a wild node - * in case we need to go searching for wildcard matches - * later on. - */ - if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0) { - search->wild = true; - } - } - - NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - - return (result); -} - -static isc_result_t -setup_delegation(qpdb_search_t *search, dns_dbnode_t **nodep, - dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { - dns_name_t *zcname = NULL; - dns_typepair_t type; - dns_qpdata_t *node = NULL; - - REQUIRE(search != NULL); - REQUIRE(search->zonecut != NULL); - REQUIRE(search->zonecut_header != NULL); - - /* - * The caller MUST NOT be holding any node locks. - */ - - node = search->zonecut; - type = search->zonecut_header->type; - - /* - * If we have to set foundname, we do it before anything else. - * If we were to set foundname after we had set nodep or bound the - * rdataset, then we'd have to undo that work if dns_name_copy() - * failed. By setting foundname first, there's nothing to undo if - * we have trouble. - */ - if (foundname != NULL && search->copy_name) { - zcname = dns_fixedname_name(&search->zonecut_name); - dns_name_copy(zcname, foundname); - } - if (nodep != NULL) { - /* - * Note that we don't have to increment the node's reference - * count here because we're going to use the reference we - * already have in the search block. - */ - *nodep = node; - search->need_cleanup = false; - } - if (rdataset != NULL) { - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - dns__qpdb_bindrdataset( - search->qpdb, node, search->zonecut_header, search->now, - isc_rwlocktype_read, rdataset DNS__DB_FLARG_PASS); - if (sigrdataset != NULL && search->zonecut_sigheader != NULL) { - dns__qpdb_bindrdataset(search->qpdb, node, - search->zonecut_sigheader, - search->now, isc_rwlocktype_read, - sigrdataset DNS__DB_FLARG_PASS); - } - NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - } - - if (type == dns_rdatatype_dname) { - return (DNS_R_DNAME); - } - return (DNS_R_DELEGATION); -} - -typedef enum { FORWARD, BACK } direction_t; - -/* - * Step backwards or forwards through the database until we find a - * node with data in it for the desired version. If 'nextname' is not NULL, - * and we found a predecessor or successor, save the name we found in it. - * Return true if we found a predecessor or successor. - */ -static bool -step(qpdb_search_t *search, dns_qpiter_t *iter, direction_t direction, - dns_name_t *nextname) { - dns_fixedname_t fnodename; - dns_name_t *nodename = dns_fixedname_initname(&fnodename); - dns_qpdb_t *qpdb = NULL; - dns_qpdata_t *node = NULL; - isc_result_t result = ISC_R_SUCCESS; - dns_slabheader_t *header = NULL; - - qpdb = search->qpdb; - - result = dns_qpiter_current(iter, nodename, (void **)&node, NULL); - - while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - NODE_RDLOCK(&(qpdb->node_locks[node->locknum].lock), - &nlocktype); - for (header = node->data; header != NULL; header = header->next) - { - if (header->serial <= search->serial && - !IGNORE(header) && EXISTS(header)) - { - break; - } - } - NODE_UNLOCK(&(qpdb->node_locks[node->locknum].lock), - &nlocktype); - if (header != NULL) { - break; - } - - if (direction == FORWARD) { - result = dns_qpiter_next(iter, nodename, (void **)&node, - NULL); - } else { - result = dns_qpiter_prev(iter, nodename, (void **)&node, - NULL); - } - }; - if (result == ISC_R_SUCCESS) { - if (nextname != NULL) { - dns_name_copy(nodename, nextname); - } - return (true); - } - return (false); -} - -/* - * Use step() to find the successor to the current name, and then - * check to see whether it's a subdomain of the current name. If so, - * then this is an empty non-terminal in the currently active version - * of the database. - */ -static bool -activeempty(qpdb_search_t *search, dns_qpiter_t *iter, - const dns_name_t *current) { - isc_result_t result; - dns_fixedname_t fnext; - dns_name_t *next = dns_fixedname_initname(&fnext); - - result = dns_qpiter_next(iter, NULL, NULL, NULL); - if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { - return (false); - } - return (step(search, iter, FORWARD, next) && - dns_name_issubdomain(next, current)); -} - -static bool -wildcard_blocked(qpdb_search_t *search, const dns_name_t *qname, - dns_name_t *wname) { - isc_result_t result; - dns_fixedname_t fnext; - dns_fixedname_t fprev; - dns_name_t *next = NULL, *prev = NULL; - dns_name_t name; - dns_name_t rname; - dns_name_t tname; - dns_qpiter_t iter; - bool check_next = false; - bool check_prev = false; - unsigned int n; - - dns_name_init(&name, NULL); - dns_name_init(&tname, NULL); - dns_name_init(&rname, NULL); - next = dns_fixedname_initname(&fnext); - prev = dns_fixedname_initname(&fprev); - - /* - * The qname seems to have matched a wildcard, but we - * need to find out if there's an empty nonterminal node - * between the wildcard level and the qname. - * - * search->iter should now be pointing at the predecessor - * of the searched-for name. We are using a local copy of the - * iterator so as not to change the state of search->iter. - * step() will walk backward until we find a predecessor with - * data. - */ - iter = search->iter; - check_prev = step(search, &iter, BACK, prev); - - /* Now reset the iterator and look for a successor with data. */ - iter = search->iter; - result = dns_qpiter_next(&iter, NULL, NULL, NULL); - if (result == ISC_R_SUCCESS) { - check_next = step(search, &iter, FORWARD, next); - } - - if (!check_prev && !check_next) { - /* No predecessor or successor was found at all? */ - return (false); - } - - dns_name_clone(qname, &rname); - - /* - * Remove the wildcard label to find the terminal name. - */ - n = dns_name_countlabels(wname); - dns_name_getlabelsequence(wname, 1, n - 1, &tname); - - do { - if ((check_prev && dns_name_issubdomain(prev, &rname)) || - (check_next && dns_name_issubdomain(next, &rname))) - { - return (true); - } - - /* - * Remove the leftmost label from the qname and check again. - */ - n = dns_name_countlabels(&rname); - dns_name_getlabelsequence(&rname, 1, n - 1, &rname); - } while (!dns_name_equal(&rname, &tname)); - - return (false); -} - -static isc_result_t -find_wildcard(qpdb_search_t *search, dns_qpdata_t **nodep, - const dns_name_t *qname) { - dns_slabheader_t *header = NULL; - isc_result_t result = ISC_R_NOTFOUND; - dns_qpdb_t *qpdb = NULL; - bool wild, active; - - /* - * Caller must be holding the tree lock and MUST NOT be holding - * any node locks. - */ - - /* - * Examine each ancestor level. If the level's wild bit - * is set, then construct the corresponding wildcard name and - * search for it. If the wildcard node exists, and is active in - * this version, we're done. If not, then we next check to see - * if the ancestor is active in this version. If so, then there - * can be no possible wildcard match and again we're done. If not, - * continue the search. - */ - - qpdb = search->qpdb; - for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { - dns_qpdata_t *node = NULL; - isc_rwlock_t *lock = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL); - lock = &qpdb->node_locks[node->locknum].lock; - - NODE_RDLOCK(lock, &nlocktype); - /* - * First we try to figure out if this node is active in - * the search's version. We do this now, even though we - * may not need the information, because it simplifies the - * locking and code flow. - */ - for (header = node->data; header != NULL; header = header->next) - { - if (header->serial <= search->serial && - !IGNORE(header) && EXISTS(header) && - !ANCIENT(header)) - { - break; - } - } - active = (header != NULL); - wild = node->wild; - NODE_UNLOCK(lock, &nlocktype); - - if (wild) { - dns_qpdata_t *wnode = NULL; - dns_fixedname_t fwname; - dns_name_t *wname = NULL; - dns_qpiter_t witer; - - /* - * Construct the wildcard name for this level. - */ - wname = dns_fixedname_initname(&fwname); - result = dns_name_concatenate(dns_wildcardname, - node->name, wname, NULL); - if (result != ISC_R_SUCCESS) { - break; - } - - wnode = NULL; - result = dns_qp_lookup(qpdb->tree, wname, NULL, &witer, - NULL, (void **)&wnode, NULL); - if (result == ISC_R_SUCCESS) { - /* - * We have found the wildcard node. If it - * is active in the search's version, we're - * done. - */ - lock = &qpdb->node_locks[wnode->locknum].lock; - NODE_RDLOCK(lock, &nlocktype); - for (header = wnode->data; header != NULL; - header = header->next) - { - if (header->serial <= search->serial && - !IGNORE(header) && EXISTS(header) && - !ANCIENT(header)) - { - break; - } - } - NODE_UNLOCK(lock, &nlocktype); - if (header != NULL || - activeempty(search, &witer, wname)) - { - if (wildcard_blocked(search, qname, - wname)) - { - return (ISC_R_NOTFOUND); - } - /* - * The wildcard node is active! - * - * Note: result is still ISC_R_SUCCESS - * so we don't have to set it. - */ - *nodep = wnode; - break; - } - } else if (result != ISC_R_NOTFOUND && - result != DNS_R_PARTIALMATCH) - { - /* - * An error has occurred. Bail out. - */ - break; - } - } - - if (active) { - /* - * The level node is active. Any wildcarding - * present at higher levels has no - * effect and we're done. - */ - result = ISC_R_NOTFOUND; - break; - } - } - - return (result); -} - -static bool -matchparams(dns_slabheader_t *header, qpdb_search_t *search) { - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_nsec3_t nsec3; - unsigned char *raw = NULL; - unsigned int rdlen, count; - isc_region_t region; - isc_result_t result; - - REQUIRE(header->type == dns_rdatatype_nsec3); - - raw = (unsigned char *)header + sizeof(*header); - count = raw[0] * 256 + raw[1]; /* count */ - raw += DNS_RDATASET_COUNT + DNS_RDATASET_LENGTH; - - while (count-- > 0) { - rdlen = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; - region.base = raw; - region.length = rdlen; - dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass, - dns_rdatatype_nsec3, ®ion); - raw += rdlen; - result = dns_rdata_tostruct(&rdata, &nsec3, NULL); - INSIST(result == ISC_R_SUCCESS); - if (nsec3.hash == search->rbtversion->hash && - nsec3.iterations == search->rbtversion->iterations && - nsec3.salt_length == search->rbtversion->salt_length && - memcmp(nsec3.salt, search->rbtversion->salt, - nsec3.salt_length) == 0) - { - return (true); - } - dns_rdata_reset(&rdata); - } - return (false); -} - -/* - * Find node of the NSEC/NSEC3 record that is 'name'. - */ -static isc_result_t -previous_closest_nsec(dns_rdatatype_t type, qpdb_search_t *search, - dns_name_t *name, dns_name_t *origin, - dns_qpdata_t **nodep, dns_qpiter_t *nseciter, - bool *firstp) { - dns_fixedname_t ftarget; - dns_name_t *target = NULL; - dns_qpdata_t *nsecnode = NULL; - isc_result_t result; - - REQUIRE(nodep != NULL && *nodep == NULL); - REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL); - - if (type == dns_rdatatype_nsec3) { - return (dns_qpiter_prev(&search->iter, name, (void **)nodep, - NULL)); - } - - target = dns_fixedname_initname(&ftarget); - - for (;;) { - if (*firstp) { - /* - * Construct the name of the second node to check. - * It is the first node sought in the NSEC tree. - */ - *firstp = false; - result = dns_name_concatenate(name, origin, target, - NULL); - if (result != ISC_R_SUCCESS) { - return (result); - } - nsecnode = NULL; - result = dns_qp_lookup(search->qpdb->nsec, name, NULL, - nseciter, NULL, - (void **)&nsecnode, NULL); - if (result == ISC_R_SUCCESS) { - /* - * Since this was the first loop, finding the - * name in the NSEC tree implies that the first - * node checked in the main tree had an - * unacceptable NSEC record. - * Try the previous node in the NSEC tree. - */ - result = dns_qpiter_prev(nseciter, name, NULL, - NULL); - if (result == DNS_R_NEWORIGIN) { - result = ISC_R_SUCCESS; - } - } else if (result == ISC_R_NOTFOUND || - result == DNS_R_PARTIALMATCH) - { - /* The iterator is already where we want it */ - result = dns_qpiter_current(nseciter, name, - NULL, NULL); - } - } else { - /* - * This is a second or later trip through the auxiliary - * tree for the name of a third or earlier NSEC node in - * the main tree. Previous trips through the NSEC tree - * must have found nodes in the main tree with NSEC - * records. Perhaps they lacked signature records. - */ - result = dns_qpiter_prev(nseciter, name, NULL, NULL); - if (result == DNS_R_NEWORIGIN) { - result = ISC_R_SUCCESS; - } - } - if (result != ISC_R_SUCCESS) { - return (result); - } - - *nodep = NULL; - result = dns_qp_lookup(search->qpdb->tree, name, NULL, - &search->iter, &search->chain, - (void **)nodep, NULL); - if (result == ISC_R_SUCCESS) { - return (result); - } - - /* - * There should always be a node in the main tree with the - * same name as the node in the auxiliary NSEC tree, except for - * nodes in the auxiliary tree that are awaiting deletion. - */ - if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_ERROR, - "previous_closest_nsec(): %s", - isc_result_totext(result)); - return (DNS_R_BADDB); - } - } -} - -/* - * Find the NSEC/NSEC3 which is or before the current point on the - * search chain. For NSEC3 records only NSEC3 records that match the - * current NSEC3PARAM record are considered. - */ -static isc_result_t -find_closest_nsec(qpdb_search_t *search, dns_dbnode_t **nodep, - dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset, dns_qp_t *tree, - bool secure DNS__DB_FLARG) { - dns_qpdata_t *node = NULL, *prevnode = NULL; - dns_slabheader_t *header = NULL, *header_next = NULL; - dns_qpiter_t nseciter; - bool empty_node; - isc_result_t result; - dns_fixedname_t fname, forigin; - dns_name_t *name = NULL, *origin = NULL; - dns_rdatatype_t type; - dns_typepair_t sigtype; - bool wraps; - bool first = true; - bool need_sig = secure; - - if (tree == search->qpdb->nsec3) { - type = dns_rdatatype_nsec3; - sigtype = DNS_SIGTYPE(dns_rdatatype_nsec3); - wraps = true; - } else { - type = dns_rdatatype_nsec; - sigtype = DNS_SIGTYPE(dns_rdatatype_nsec); - wraps = false; - } - - /* - * Use the auxiliary tree only starting with the second node in the - * hope that the original node will be right much of the time. - */ - name = dns_fixedname_initname(&fname); - origin = dns_fixedname_initname(&forigin); - - result = dns_qpiter_current(&search->iter, name, (void **)&node, NULL); - if (result != ISC_R_SUCCESS) { - return (result); - } - -again: - do { - dns_slabheader_t *found = NULL, *foundsig = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - empty_node = true; - for (header = node->data; header != NULL; header = header_next) - { - header_next = header->next; - /* - * Look for an active, extant NSEC or RRSIG NSEC. - */ - do { - if (header->serial <= search->serial && - !IGNORE(header)) - { - /* - * Is this a "this rdataset doesn't - * exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - /* - * We now know that there is at least one - * active rdataset at this node. - */ - empty_node = false; - if (header->type == type) { - found = header; - if (foundsig != NULL) { - break; - } - } else if (header->type == sigtype) { - foundsig = header; - if (found != NULL) { - break; - } - } - } - } - if (!empty_node) { - if (found != NULL && search->rbtversion->havensec3 && - found->type == dns_rdatatype_nsec3 && - !matchparams(found, search)) - { - empty_node = true; - found = NULL; - foundsig = NULL; - result = previous_closest_nsec( - type, search, name, origin, &prevnode, - NULL, NULL); - } else if (found != NULL && - (foundsig != NULL || !need_sig)) - { - /* - * We've found the right NSEC/NSEC3 record. - * - * Note: for this to really be the right - * NSEC record, it's essential that the NSEC - * records of any nodes obscured by a zone - * cut have been removed; we assume this is - * the case. - */ - result = dns_name_concatenate(name, origin, - foundname, NULL); - if (result == ISC_R_SUCCESS) { - if (nodep != NULL) { - dns__qpdb_newref( - search->qpdb, node, - isc_rwlocktype_read - DNS__DB_FLARG_PASS); - *nodep = node; - } - dns__qpdb_bindrdataset( - search->qpdb, node, found, - search->now, - isc_rwlocktype_read, - rdataset DNS__DB_FLARG_PASS); - if (foundsig != NULL) { - dns__qpdb_bindrdataset( - search->qpdb, node, - foundsig, search->now, - isc_rwlocktype_read, - sigrdataset - DNS__DB_FLARG_PASS); - } - } - } else if (found == NULL && foundsig == NULL) { - /* - * This node is active, but has no NSEC or - * RRSIG NSEC. That means it's glue or - * other obscured zone data that isn't - * relevant for our search. Treat the - * node as if it were empty and keep looking. - */ - empty_node = true; - result = previous_closest_nsec( - type, search, name, origin, &prevnode, - &nseciter, &first); - } else { - /* - * We found an active node, but either the - * NSEC or the RRSIG NSEC is missing. This - * shouldn't happen. - */ - result = DNS_R_BADDB; - } - } else { - /* - * This node isn't active. We've got to keep - * looking. - */ - result = previous_closest_nsec(type, search, name, - origin, &prevnode, - &nseciter, &first); - } - NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), - &nlocktype); - node = prevnode; - prevnode = NULL; - } while (empty_node && result == ISC_R_SUCCESS); - - if (result == ISC_R_NOMORE && wraps) { - result = dns_qpiter_prev(&search->iter, name, (void **)&node, - NULL); - if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { - wraps = false; - goto again; - } - } - - /* - * If the result is ISC_R_NOMORE, then we got to the beginning of - * the database and didn't find a NSEC record. This shouldn't - * happen. - */ - if (result == ISC_R_NOMORE) { - result = DNS_R_BADDB; - } - - return (result); -} - -static isc_result_t -zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, - dns_rdatatype_t type, unsigned int options, - isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep, - dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { - dns_qpdata_t *node = NULL; - isc_result_t result; - qpdb_search_t search; - bool cname_ok = true; - bool close_version = false; - bool maybe_zonecut = false; - bool at_zonecut = false; - bool wild = false; - bool empty_node; - dns_slabheader_t *header = NULL, *header_next = NULL; - dns_slabheader_t *found = NULL, *nsecheader = NULL; - dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL; - dns_typepair_t sigtype; - bool active; - isc_rwlock_t *lock = NULL; - dns_qp_t *tree = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB((dns_qpdb_t *)db)); - INSIST(version == NULL || - ((dns_qpdb_version_t *)version)->qpdb == (dns_qpdb_t *)db); - - /* - * If the caller didn't supply a version, attach to the current - * version. - */ - if (version == NULL) { - dns__qpdb_currentversion(db, &version); - close_version = true; - } - - search = (qpdb_search_t){ - .qpdb = (dns_qpdb_t *)db, - .rbtversion = version, - .serial = ((dns_qpdb_version_t *)version)->serial, - .options = options, - }; - dns_fixedname_init(&search.zonecut_name); - - TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype); - - /* - * Search down from the root of the tree. - */ - tree = (options & DNS_DBFIND_FORCENSEC3) != 0 ? search.qpdb->nsec3 - : search.qpdb->tree; - 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_qpdata_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: - if (search.zonecut != NULL) { - result = setup_delegation( - &search, nodep, foundname, rdataset, - sigrdataset DNS__DB_FLARG_PASS); - goto tree_exit; - } - - if (search.wild) { - /* - * At least one of the levels in the search chain - * potentially has a wildcard. For each such level, - * we must see if there's a matching wildcard active - * in the current version. - */ - result = find_wildcard(&search, &node, name); - if (result == ISC_R_SUCCESS) { - dns_name_copy(name, foundname); - wild = true; - goto found; - } else if (result != ISC_R_NOTFOUND) { - goto tree_exit; - } - } - - active = false; - if ((options & DNS_DBFIND_FORCENSEC3) == 0) { - /* - * The NSEC3 tree won't have empty nodes, - * so it isn't necessary to check for them. - */ - dns_qpiter_t iter = search.iter; - active = activeempty(&search, &iter, name); - } - - /* - * If we're here, then the name does not exist, is not - * beneath a zonecut, and there's no matching wildcard. - */ - if ((search.rbtversion->secure && - !search.rbtversion->havensec3) || - (search.options & DNS_DBFIND_FORCENSEC3) != 0) - { - result = find_closest_nsec( - &search, nodep, foundname, rdataset, - sigrdataset, tree, - search.rbtversion->secure DNS__DB_FLARG_PASS); - if (result == ISC_R_SUCCESS) { - result = active ? DNS_R_EMPTYNAME - : DNS_R_NXDOMAIN; - } - } else { - result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN; - } - goto tree_exit; - } else if (result != ISC_R_SUCCESS) { - goto tree_exit; - } - -found: - /* - * We have found a node whose name is the desired name, or we - * 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 - * CNAMEs because they're not legitimate zone glue. - */ - cname_ok = false; - } else { - /* - * The node may be a zone cut itself. If it might be one, - * make sure we check for it later. - * - * DS records live above the zone cut in ordinary zone so - * we want to ignore any referral. - * - * Stub zones don't have anything "above" the delegation so - * we always return a referral. - */ - if (node->find_callback && ((node != search.qpdb->origin_node && - !dns_rdatatype_atparent(type)) || - IS_STUB(search.qpdb))) - { - maybe_zonecut = true; - } - } - - /* - * Certain DNSSEC types are not subject to CNAME matching - * (RFC4035, section 2.5 and RFC3007). - * - * We don't check for RRSIG, because we don't store RRSIG records - * directly. - */ - if (type == dns_rdatatype_key || type == dns_rdatatype_nsec) { - cname_ok = false; - } - - /* - * We now go looking for rdata... - */ - - found = NULL; - foundsig = NULL; - sigtype = DNS_SIGTYPE(type); - nsecheader = NULL; - nsecsig = NULL; - cnamesig = NULL; - empty_node = true; - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - /* - * Look for an active, extant rdataset. - */ - do { - if (header->serial <= search.serial && !IGNORE(header)) - { - /* - * Is this a "this rdataset doesn't - * exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - /* - * We now know that there is at least one active - * rdataset at this node. - */ - empty_node = false; - - /* - * Do special zone cut handling, if requested. - */ - if (maybe_zonecut && header->type == dns_rdatatype_ns) { - /* - * We increment the reference count on node to - * ensure that search->zonecut_header will - * still be valid later. - */ - dns__qpdb_newref(search.qpdb, node, - nlocktype DNS__DB_FLARG_PASS); - search.zonecut = node; - search.zonecut_header = header; - search.zonecut_sigheader = NULL; - search.need_cleanup = true; - maybe_zonecut = false; - at_zonecut = true; - /* - * It is not clear if KEY should still be - * allowed at the parent side of the zone - * cut or not. It is needed for RFC3007 - * validated updates. - */ - if ((search.options & DNS_DBFIND_GLUEOK) == 0 && - type != dns_rdatatype_nsec && - type != dns_rdatatype_key) - { - /* - * Glue is not OK, but any answer we - * could return would be glue. Return - * the delegation. - */ - found = NULL; - break; - } - if (found != NULL && foundsig != NULL) { - break; - } - } - - /* - * If the NSEC3 record doesn't match the chain - * we are using behave as if it isn't here. - */ - if (header->type == dns_rdatatype_nsec3 && - !matchparams(header, &search)) - { - NODE_UNLOCK(lock, &nlocktype); - goto partial_match; - } - /* - * If we found a type we were looking for, - * remember it. - */ - if (header->type == type || type == dns_rdatatype_any || - (header->type == dns_rdatatype_cname && cname_ok)) - { - /* - * We've found the answer! - */ - found = header; - if (header->type == dns_rdatatype_cname && - cname_ok) - { - /* - * We may be finding a CNAME instead - * of the desired type. - * - * If we've already got the CNAME RRSIG, - * use it, otherwise change sigtype - * so that we find it. - */ - if (cnamesig != NULL) { - foundsig = cnamesig; - } else { - sigtype = DNS_SIGTYPE( - dns_rdatatype_cname); - } - } - /* - * If we've got all we need, end the search. - */ - if (!maybe_zonecut && foundsig != NULL) { - break; - } - } else if (header->type == sigtype) { - /* - * We've found the RRSIG rdataset for our - * target type. Remember it. - */ - foundsig = header; - /* - * If we've got all we need, end the search. - */ - if (!maybe_zonecut && found != NULL) { - break; - } - } else if (header->type == dns_rdatatype_nsec && - !search.rbtversion->havensec3) - { - /* - * Remember a NSEC rdataset even if we're - * not specifically looking for it, because - * we might need it later. - */ - nsecheader = header; - } else if (header->type == - DNS_SIGTYPE(dns_rdatatype_nsec) && - !search.rbtversion->havensec3) - { - /* - * If we need the NSEC rdataset, we'll also - * need its signature. - */ - nsecsig = header; - } else if (cname_ok && - header->type == - DNS_SIGTYPE(dns_rdatatype_cname)) - { - /* - * If we get a CNAME match, we'll also need - * its signature. - */ - cnamesig = header; - } - } - } - - if (empty_node) { - /* - * We have an exact match for the name, but there are no - * active rdatasets in the desired version. That means that - * this node doesn't exist in the desired version, and that - * we really have a partial match. - */ - if (!wild) { - NODE_UNLOCK(lock, &nlocktype); - goto partial_match; - } - } - - /* - * If we didn't find what we were looking for... - */ - if (found == NULL) { - if (search.zonecut != NULL) { - /* - * We were trying to find glue at a node beneath a - * zone cut, but didn't. - * - * Return the delegation. - */ - NODE_UNLOCK(lock, &nlocktype); - result = setup_delegation( - &search, nodep, foundname, rdataset, - sigrdataset DNS__DB_FLARG_PASS); - goto tree_exit; - } - /* - * The desired type doesn't exist. - */ - result = DNS_R_NXRRSET; - if (search.rbtversion->secure && - !search.rbtversion->havensec3 && - (nsecheader == NULL || nsecsig == NULL)) - { - /* - * The zone is secure but there's no NSEC, - * or the NSEC has no signature! - */ - if (!wild) { - result = DNS_R_BADDB; - goto node_exit; - } - - NODE_UNLOCK(lock, &nlocktype); - result = find_closest_nsec( - &search, nodep, foundname, rdataset, - sigrdataset, search.qpdb->tree, - search.rbtversion->secure DNS__DB_FLARG_PASS); - if (result == ISC_R_SUCCESS) { - result = DNS_R_EMPTYWILD; - } - goto tree_exit; - } - if (nodep != NULL) { - dns__qpdb_newref(search.qpdb, node, - nlocktype DNS__DB_FLARG_PASS); - *nodep = node; - } - if ((search.rbtversion->secure && - !search.rbtversion->havensec3)) - { - dns__qpdb_bindrdataset(search.qpdb, node, nsecheader, 0, - nlocktype, - rdataset DNS__DB_FLARG_PASS); - if (nsecsig != NULL) { - dns__qpdb_bindrdataset( - search.qpdb, node, nsecsig, 0, - nlocktype, - sigrdataset DNS__DB_FLARG_PASS); - } - } - if (wild) { - foundname->attributes.wildcard = true; - } - goto node_exit; - } - - /* - * We found what we were looking for, or we found a CNAME. - */ - - if (type != found->type && type != dns_rdatatype_any && - found->type == dns_rdatatype_cname) - { - /* - * We weren't doing an ANY query and we found a CNAME instead - * of the type we were looking for, so we need to indicate - * that result to the caller. - */ - result = DNS_R_CNAME; - } else if (search.zonecut != NULL) { - /* - * If we're beneath a zone cut, we must indicate that the - * result is glue, unless we're actually at the zone cut - * and the type is NSEC or KEY. - */ - if (search.zonecut == node) { - /* - * It is not clear if KEY should still be - * allowed at the parent side of the zone - * cut or not. It is needed for RFC3007 - * validated updates. - */ - if (type == dns_rdatatype_nsec || - type == dns_rdatatype_nsec3 || - type == dns_rdatatype_key) - { - result = ISC_R_SUCCESS; - } else if (type == dns_rdatatype_any) { - result = DNS_R_ZONECUT; - } else { - result = DNS_R_GLUE; - } - } else { - result = DNS_R_GLUE; - } - } else { - /* - * An ordinary successful query! - */ - result = ISC_R_SUCCESS; - } - - if (nodep != NULL) { - if (!at_zonecut) { - dns__qpdb_newref(search.qpdb, node, - nlocktype DNS__DB_FLARG_PASS); - } else { - search.need_cleanup = false; - } - *nodep = node; - } - - if (type != dns_rdatatype_any) { - dns__qpdb_bindrdataset(search.qpdb, node, found, 0, nlocktype, - rdataset DNS__DB_FLARG_PASS); - if (foundsig != NULL) { - dns__qpdb_bindrdataset(search.qpdb, node, foundsig, 0, - nlocktype, - sigrdataset DNS__DB_FLARG_PASS); - } - } - - if (wild) { - foundname->attributes.wildcard = true; - } - -node_exit: - NODE_UNLOCK(lock, &nlocktype); - -tree_exit: - TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype); - - /* - * If we found a zonecut but aren't going to use it, we have to - * let go of it. - */ - if (search.need_cleanup) { - node = search.zonecut; - INSIST(node != NULL); - lock = &(search.qpdb->node_locks[node->locknum].lock); - - NODE_RDLOCK(lock, &nlocktype); - dns__qpdb_decref(search.qpdb, node, 0, &nlocktype, &tlocktype, - true, false DNS__DB_FLARG_PASS); - NODE_UNLOCK(lock, &nlocktype); - INSIST(tlocktype == isc_rwlocktype_none); - } - - if (close_version) { - dns__qpdb_closeversion(db, &version, false DNS__DB_FLARG_PASS); - } - - return (result); -} - -static isc_result_t -zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - dns_rdatatype_t type, dns_rdatatype_t covers, - isc_stdtime_t now, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - dns_slabheader_t *header = NULL, *header_next = NULL; - dns_slabheader_t *found = NULL, *foundsig = NULL; - uint32_t serial; - dns_qpdb_version_t *rbtversion = version; - bool close_version = false; - dns_typepair_t matchtype, sigmatchtype; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(type != dns_rdatatype_any); - INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb); - - if (rbtversion == NULL) { - dns__qpdb_currentversion( - db, (dns_dbversion_t **)(void *)(&rbtversion)); - close_version = true; - } - serial = rbtversion->serial; - now = 0; - - NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - - matchtype = DNS_TYPEPAIR_VALUE(type, covers); - if (covers == 0) { - sigmatchtype = DNS_SIGTYPE(type); - } else { - sigmatchtype = 0; - } - - for (header = qpnode->data; header != NULL; header = header_next) { - header_next = header->next; - do { - if (header->serial <= serial && !IGNORE(header)) { - /* - * Is this a "this rdataset doesn't - * exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - /* - * We have an active, extant rdataset. If it's a - * type we're looking for, remember it. - */ - if (header->type == matchtype) { - found = header; - if (foundsig != NULL) { - break; - } - } else if (header->type == sigmatchtype) { - foundsig = header; - if (found != NULL) { - break; - } - } - } - } - if (found != NULL) { - dns__qpdb_bindrdataset(qpdb, qpnode, found, now, - isc_rwlocktype_read, - rdataset DNS__DB_FLARG_PASS); - if (foundsig != NULL) { - dns__qpdb_bindrdataset(qpdb, qpnode, foundsig, now, - isc_rwlocktype_read, - sigrdataset DNS__DB_FLARG_PASS); - } - } - - NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - - if (close_version) { - dns__qpdb_closeversion( - db, (dns_dbversion_t **)(void *)(&rbtversion), - false DNS__DB_FLARG_PASS); - } - - if (found == NULL) { - return (ISC_R_NOTFOUND); - } - - return (ISC_R_SUCCESS); -} - -static bool -delegating_type(dns_qpdb_t *qpdb, dns_qpdata_t *node, dns_typepair_t type) { - if (type == dns_rdatatype_dname || - (type == dns_rdatatype_ns && - (node != qpdb->origin_node || IS_STUB(qpdb)))) - { - return (true); - } - return (false); -} - -/* - * load a non-NSEC3 node in the main tree and optionally to the auxiliary NSEC - */ -static isc_result_t -loadnode(dns_qpdb_t *qpdb, const dns_name_t *name, dns_qpdata_t **nodep, - bool hasnsec) { - isc_result_t noderesult, nsecresult; - dns_qpdata_t *nsecnode = NULL, *node = NULL; - - noderesult = dns_qp_getname(qpdb->tree, name, (void **)&node, NULL); - if (noderesult != ISC_R_SUCCESS) { - INSIST(node == NULL); - node = dns_qpdata_create(qpdb, name); - noderesult = dns_qp_insert(qpdb->tree, node, 0); - INSIST(noderesult == ISC_R_SUCCESS); - dns_qpdata_unref(node); - } else if (noderesult == ISC_R_SUCCESS) { - /* - * Add a node to the auxiliary NSEC tree for an old node - * just now getting an NSEC record. - */ - if (node->nsec == DNS_DB_NSEC_HAS_NSEC) { - goto done; - } - } else { - goto done; - } - - if (!hasnsec) { - goto done; - } - - /* - * Build the auxiliary tree for NSECs as we go. - * This tree speeds searches for closest NSECs that would otherwise - * need to examine many irrelevant nodes in large TLDs. - * - * Add nodes to the auxiliary tree after corresponding nodes have - * been added to the main tree. - */ - nsecresult = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode, NULL); - if (nsecresult == ISC_R_SUCCESS) { -#if 1 /* 0 */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, - "addnode: NSEC node already exists"); -#endif /* if 1 */ - node->nsec = DNS_DB_NSEC_HAS_NSEC; - goto done; - } else { - INSIST(nsecnode == NULL); - nsecnode = dns_qpdata_create(qpdb, name); - nsecnode->nsec = DNS_DB_NSEC_NSEC; - nsecresult = dns_qp_insert(qpdb->nsec, nsecnode, 0); - INSIST(nsecresult == ISC_R_SUCCESS); - dns_qpdata_detach(&nsecnode); - } - node->nsec = DNS_DB_NSEC_HAS_NSEC; - -done: - if (noderesult == ISC_R_SUCCESS || noderesult == ISC_R_EXISTS) { - *nodep = node; - } - - return (noderesult); -} - -static isc_result_t -loading_addrdataset(void *arg, const dns_name_t *name, - dns_rdataset_t *rdataset DNS__DB_FLARG) { - qpdb_load_t *loadctx = arg; - dns_qpdb_t *qpdb = (dns_qpdb_t *)loadctx->db; - dns_qpdata_t *node = NULL; - isc_result_t result; - isc_region_t region; - dns_slabheader_t *newheader = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - REQUIRE(rdataset->rdclass == qpdb->common.rdclass); - - /* - * SOA records are only allowed at top of zone. - */ - if (rdataset->type == dns_rdatatype_soa && - !dns_name_equal(name, &qpdb->common.origin)) - { - return (DNS_R_NOTZONETOP); - } - - if (rdataset->type != dns_rdatatype_nsec3 && - rdataset->covers != dns_rdatatype_nsec3) - { - dns__qpzone_addwildcards(qpdb, name, false); - } - - if (dns_name_iswildcard(name)) { - /* - * NS record owners cannot legally be wild cards. - */ - if (rdataset->type == dns_rdatatype_ns) { - return (DNS_R_INVALIDNS); - } - /* - * NSEC3 record owners cannot legally be wild cards. - */ - if (rdataset->type == dns_rdatatype_nsec3) { - return (DNS_R_INVALIDNSEC3); - } - result = dns__qpzone_wildcardmagic(qpdb, name, false); - if (result != ISC_R_SUCCESS) { - return (result); - } - } - - if (rdataset->type == dns_rdatatype_nsec3 || - rdataset->covers == dns_rdatatype_nsec3) - { - result = dns_qp_getname(qpdb->nsec3, name, (void **)&node, - NULL); - if (result != ISC_R_SUCCESS) { - INSIST(node == NULL); - node = dns_qpdata_create(qpdb, name); - result = dns_qp_insert(qpdb->nsec3, node, 0); - INSIST(result == ISC_R_SUCCESS); - dns_qpdata_unref(node); - } - node->nsec = DNS_DB_NSEC_NSEC3; - } else if (rdataset->type == dns_rdatatype_nsec) { - result = loadnode(qpdb, name, &node, true); - } else { - result = loadnode(qpdb, name, &node, false); - } - if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) { - return (result); - } - if (result == ISC_R_SUCCESS) { - node->locknum = node->hashval % qpdb->node_lock_count; - } - - result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, - ®ion, sizeof(dns_slabheader_t)); - if (result != ISC_R_SUCCESS) { - return (result); - } - newheader = (dns_slabheader_t *)region.base; - *newheader = (dns_slabheader_t){ - .type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers), - .ttl = rdataset->ttl + loadctx->now, - .trust = rdataset->trust, - .node = node, - .serial = 1, - .count = 1, - }; - - dns_slabheader_reset(newheader, (dns_db_t *)qpdb, node); - dns_slabheader_setownercase(newheader, name); - - if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); - newheader->resign = - (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> - 1); - newheader->resign_lsb = rdataset->resign & 0x1; - } - - NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); - result = dns__qpdb_add(qpdb, node, name, qpdb->current_version, - newheader, DNS_DBADD_MERGE, true, NULL, - 0 DNS__DB_FLARG_PASS); - NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); - - if (result == ISC_R_SUCCESS && - delegating_type(qpdb, node, rdataset->type)) - { - node->find_callback = 1; - } else if (result == DNS_R_UNCHANGED) { - result = ISC_R_SUCCESS; - } - - return (result); -} - -static isc_result_t -beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { - qpdb_load_t *loadctx = NULL; - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - - REQUIRE(DNS_CALLBACK_VALID(callbacks)); - REQUIRE(VALID_QPDB(qpdb)); - - loadctx = isc_mem_get(qpdb->common.mctx, sizeof(*loadctx)); - - loadctx->db = db; - loadctx->now = 0; - - RWLOCK(&qpdb->lock, isc_rwlocktype_write); - - REQUIRE((qpdb->attributes & (QPDB_ATTR_LOADED | QPDB_ATTR_LOADING)) == - 0); - qpdb->attributes |= QPDB_ATTR_LOADING; - - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - - callbacks->add = loading_addrdataset; - callbacks->add_private = loadctx; - - return (ISC_R_SUCCESS); -} - -static isc_result_t -endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { - qpdb_load_t *loadctx = NULL; - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(DNS_CALLBACK_VALID(callbacks)); - loadctx = callbacks->add_private; - REQUIRE(loadctx != NULL); - REQUIRE(loadctx->db == db); - - RWLOCK(&qpdb->lock, isc_rwlocktype_write); - - REQUIRE((qpdb->attributes & QPDB_ATTR_LOADING) != 0); - REQUIRE((qpdb->attributes & QPDB_ATTR_LOADED) == 0); - - qpdb->attributes &= ~QPDB_ATTR_LOADING; - qpdb->attributes |= QPDB_ATTR_LOADED; - - /* - * If there's a KEY rdataset at the zone origin containing a - * zone key, we consider the zone secure. - */ - if (qpdb->origin_node != NULL) { - dns_dbversion_t *version = qpdb->current_version; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - dns__qpdb_setsecure(db, version, qpdb->origin_node); - } else { - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - } - - callbacks->add = NULL; - callbacks->add_private = NULL; - - isc_mem_put(qpdb->common.mctx, loadctx, sizeof(*loadctx)); - - return (ISC_R_SUCCESS); -} - -static bool -issecure(dns_db_t *db) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - bool secure; - - REQUIRE(VALID_QPDB(qpdb)); - - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - secure = qpdb->current_version->secure; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - - return (secure); -} - -static isc_result_t -getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash, - uint8_t *flags, uint16_t *iterations, unsigned char *salt, - size_t *salt_length) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - isc_result_t result = ISC_R_NOTFOUND; - dns_qpdb_version_t *rbtversion = version; - - REQUIRE(VALID_QPDB(qpdb)); - INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb); - - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - if (rbtversion == NULL) { - rbtversion = qpdb->current_version; - } - - if (rbtversion->havensec3) { - if (hash != NULL) { - *hash = rbtversion->hash; - } - if (salt != NULL && salt_length != NULL) { - REQUIRE(*salt_length >= rbtversion->salt_length); - memmove(salt, rbtversion->salt, - rbtversion->salt_length); - } - if (salt_length != NULL) { - *salt_length = rbtversion->salt_length; - } - if (iterations != NULL) { - *iterations = rbtversion->iterations; - } - if (flags != NULL) { - *flags = rbtversion->flags; - } - result = ISC_R_SUCCESS; - } - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - - return (result); -} - -static isc_result_t -getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records, - uint64_t *xfrsize) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - isc_result_t result = ISC_R_SUCCESS; - dns_qpdb_version_t *rbtversion = version; - - REQUIRE(VALID_QPDB(qpdb)); - INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb); - - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - if (rbtversion == NULL) { - rbtversion = qpdb->current_version; - } - - RWLOCK(&rbtversion->rwlock, isc_rwlocktype_read); - SET_IF_NOT_NULL(records, rbtversion->records); - - SET_IF_NOT_NULL(xfrsize, rbtversion->xfrsize); - RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_read); - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - - return (result); -} - -static isc_result_t -setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_slabheader_t *header, oldheader; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(!IS_CACHE(qpdb)); - REQUIRE(rdataset != NULL); - REQUIRE(rdataset->methods == &dns_rdataslab_rdatasetmethods); - - header = dns_slabheader_fromrdataset(rdataset); - - NODE_WRLOCK(&qpdb->node_locks[QPDB_HEADERNODE(header)->locknum].lock, - &nlocktype); - - oldheader = *header; - - /* - * Only break the heap invariant (by adjusting resign and resign_lsb) - * if we are going to be restoring it by calling isc_heap_increased - * or isc_heap_decreased. - */ - if (resign != 0) { - header->resign = (isc_stdtime_t)(dns_time64_from32(resign) >> - 1); - header->resign_lsb = resign & 0x1; - } - if (header->heap_index != 0) { - INSIST(RESIGN(header)); - if (resign == 0) { - isc_heap_delete( - qpdb->heaps[QPDB_HEADERNODE(header)->locknum], - header->heap_index); - header->heap_index = 0; - header->heap = NULL; - } else if (qpdb->sooner(header, &oldheader)) { - isc_heap_increased( - qpdb->heaps[QPDB_HEADERNODE(header)->locknum], - header->heap_index); - } else if (qpdb->sooner(&oldheader, header)) { - isc_heap_decreased( - qpdb->heaps[QPDB_HEADERNODE(header)->locknum], - header->heap_index); - } - } else if (resign != 0) { - DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_RESIGN); - dns__qpzone_resigninsert(qpdb, QPDB_HEADERNODE(header)->locknum, - header); - } - NODE_UNLOCK(&qpdb->node_locks[QPDB_HEADERNODE(header)->locknum].lock, - &nlocktype); - return (ISC_R_SUCCESS); -} - -static isc_result_t -getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, - dns_name_t *foundname DNS__DB_FLARG) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_slabheader_t *header = NULL, *this = NULL; - unsigned int i; - isc_result_t result = ISC_R_NOTFOUND; - unsigned int locknum = 0; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB(qpdb)); - - TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); - - for (i = 0; i < qpdb->node_lock_count; i++) { - NODE_RDLOCK(&qpdb->node_locks[i].lock, &nlocktype); - - /* - * Find for the earliest signing time among all of the - * heaps, each of which is covered by a different bucket - * lock. - */ - this = isc_heap_element(qpdb->heaps[i], 1); - if (this == NULL) { - /* Nothing found; unlock and try the next heap. */ - NODE_UNLOCK(&qpdb->node_locks[i].lock, &nlocktype); - continue; - } - - if (header == NULL) { - /* - * Found a signing time: retain the bucket lock and - * preserve the lock number so we can unlock it - * later. - */ - header = this; - locknum = i; - nlocktype = isc_rwlocktype_none; - } else if (qpdb->sooner(this, header)) { - /* - * Found an earlier signing time; release the - * previous bucket lock and retain this one instead. - */ - NODE_UNLOCK(&qpdb->node_locks[locknum].lock, - &nlocktype); - header = this; - locknum = i; - } else { - /* - * Earliest signing time in this heap isn't - * an improvement; unlock and try the next heap. - */ - NODE_UNLOCK(&qpdb->node_locks[i].lock, &nlocktype); - } - } - - if (header != NULL) { - nlocktype = isc_rwlocktype_read; - /* - * Found something; pass back the answer and unlock - * the bucket. - */ - dns__qpdb_bindrdataset(qpdb, QPDB_HEADERNODE(header), header, 0, - isc_rwlocktype_read, - rdataset DNS__DB_FLARG_PASS); - - if (foundname != NULL) { - dns_name_copy(QPDB_HEADERNODE(header)->name, foundname); - } - - NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); - - result = ISC_R_SUCCESS; - } - - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - - return (result); -} - -static isc_result_t -setgluecachestats(dns_db_t *db, isc_stats_t *stats) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(!IS_CACHE(qpdb) && !IS_STUB(qpdb)); - REQUIRE(stats != NULL); - - isc_stats_attach(stats, &qpdb->gluecachestats); - return (ISC_R_SUCCESS); -} - -static dns_glue_t * -new_gluelist(isc_mem_t *mctx, dns_name_t *name) { - dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue)); - *glue = (dns_glue_t){ 0 }; - dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname); - - isc_mem_attach(mctx, &glue->mctx); - dns_name_copy(name, gluename); - - return (glue); -} - -static isc_result_t -glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, - dns_rdataset_t *unused DNS__DB_FLARG) { - dns_glue_additionaldata_ctx_t *ctx = NULL; - isc_result_t result; - dns_fixedname_t fixedname_a; - dns_name_t *name_a = NULL; - dns_rdataset_t rdataset_a, sigrdataset_a; - dns_qpdata_t *node_a = NULL; - dns_fixedname_t fixedname_aaaa; - dns_name_t *name_aaaa = NULL; - dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa; - dns_qpdata_t *node_aaaa = NULL; - dns_glue_t *glue = NULL; - - UNUSED(unused); - - /* - * NS records want addresses in additional records. - */ - INSIST(qtype == dns_rdatatype_a); - - ctx = (dns_glue_additionaldata_ctx_t *)arg; - - name_a = dns_fixedname_initname(&fixedname_a); - dns_rdataset_init(&rdataset_a); - dns_rdataset_init(&sigrdataset_a); - - name_aaaa = dns_fixedname_initname(&fixedname_aaaa); - dns_rdataset_init(&rdataset_aaaa); - dns_rdataset_init(&sigrdataset_aaaa); - - result = zone_find(ctx->db, name, ctx->version, dns_rdatatype_a, - DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, - name_a, &rdataset_a, - &sigrdataset_a DNS__DB_FLARG_PASS); - if (result == DNS_R_GLUE) { - glue = new_gluelist(ctx->db->mctx, name_a); - - dns_rdataset_init(&glue->rdataset_a); - dns_rdataset_init(&glue->sigrdataset_a); - dns_rdataset_init(&glue->rdataset_aaaa); - dns_rdataset_init(&glue->sigrdataset_aaaa); - - dns_rdataset_clone(&rdataset_a, &glue->rdataset_a); - if (dns_rdataset_isassociated(&sigrdataset_a)) { - dns_rdataset_clone(&sigrdataset_a, - &glue->sigrdataset_a); - } - } - - result = zone_find(ctx->db, name, ctx->version, dns_rdatatype_aaaa, - DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa, - name_aaaa, &rdataset_aaaa, - &sigrdataset_aaaa DNS__DB_FLARG_PASS); - if (result == DNS_R_GLUE) { - if (glue == NULL) { - glue = new_gluelist(ctx->db->mctx, name_aaaa); - - dns_rdataset_init(&glue->rdataset_a); - dns_rdataset_init(&glue->sigrdataset_a); - dns_rdataset_init(&glue->rdataset_aaaa); - dns_rdataset_init(&glue->sigrdataset_aaaa); - } else { - INSIST(node_a == node_aaaa); - INSIST(dns_name_equal(name_a, name_aaaa)); - } - - dns_rdataset_clone(&rdataset_aaaa, &glue->rdataset_aaaa); - if (dns_rdataset_isassociated(&sigrdataset_aaaa)) { - dns_rdataset_clone(&sigrdataset_aaaa, - &glue->sigrdataset_aaaa); - } - } - - /* - * If the currently processed NS record is in-bailiwick, mark any glue - * RRsets found for it with DNS_RDATASETATTR_REQUIRED. Note that for - * simplicity, glue RRsets for all in-bailiwick NS records are marked - * this way, even though dns_message_rendersection() only checks the - * attributes for the first rdataset associated with the first name - * added to the ADDITIONAL section. - */ - if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) { - if (dns_rdataset_isassociated(&glue->rdataset_a)) { - glue->rdataset_a.attributes |= - DNS_RDATASETATTR_REQUIRED; - } - if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { - glue->rdataset_aaaa.attributes |= - DNS_RDATASETATTR_REQUIRED; - } - } - - if (glue != NULL) { - glue->next = ctx->glue_list; - ctx->glue_list = glue; - } - - result = ISC_R_SUCCESS; - - if (dns_rdataset_isassociated(&rdataset_a)) { - dns_rdataset_disassociate(&rdataset_a); - } - if (dns_rdataset_isassociated(&sigrdataset_a)) { - dns_rdataset_disassociate(&sigrdataset_a); - } - - if (dns_rdataset_isassociated(&rdataset_aaaa)) { - dns_rdataset_disassociate(&rdataset_aaaa); - } - if (dns_rdataset_isassociated(&sigrdataset_aaaa)) { - dns_rdataset_disassociate(&sigrdataset_aaaa); - } - - if (node_a != NULL) { - dns__db_detachnode(ctx->db, - (dns_dbnode_t *)&node_a DNS__DB_FLARG_PASS); - } - if (node_aaaa != NULL) { - dns__db_detachnode( - ctx->db, (dns_dbnode_t *)&node_aaaa DNS__DB_FLARG_PASS); - } - - return (result); -} - -#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0) - -static void -addglue_to_message(dns_glue_t *ge, dns_message_t *msg) { - for (; ge != NULL; ge = ge->next) { - dns_name_t *name = NULL; - dns_rdataset_t *rdataset_a = NULL; - dns_rdataset_t *sigrdataset_a = NULL; - dns_rdataset_t *rdataset_aaaa = NULL; - dns_rdataset_t *sigrdataset_aaaa = NULL; - dns_name_t *gluename = dns_fixedname_name(&ge->fixedname); - bool prepend_name = false; - - dns_message_gettempname(msg, &name); - - dns_name_copy(gluename, name); - - if (dns_rdataset_isassociated(&ge->rdataset_a)) { - dns_message_gettemprdataset(msg, &rdataset_a); - } - - if (dns_rdataset_isassociated(&ge->sigrdataset_a)) { - dns_message_gettemprdataset(msg, &sigrdataset_a); - } - - if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) { - dns_message_gettemprdataset(msg, &rdataset_aaaa); - } - - if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) { - dns_message_gettemprdataset(msg, &sigrdataset_aaaa); - } - - if (rdataset_a != NULL) { - dns_rdataset_clone(&ge->rdataset_a, rdataset_a); - ISC_LIST_APPEND(name->list, rdataset_a, link); - if (IS_REQUIRED_GLUE(rdataset_a)) { - prepend_name = true; - } - } - - if (sigrdataset_a != NULL) { - dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a); - ISC_LIST_APPEND(name->list, sigrdataset_a, link); - } - - if (rdataset_aaaa != NULL) { - dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa); - ISC_LIST_APPEND(name->list, rdataset_aaaa, link); - if (IS_REQUIRED_GLUE(rdataset_aaaa)) { - prepend_name = true; - } - } - if (sigrdataset_aaaa != NULL) { - dns_rdataset_clone(&ge->sigrdataset_aaaa, - sigrdataset_aaaa); - ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link); - } - - dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); - - /* - * When looking for required glue, dns_message_rendersection() - * only processes the first rdataset associated with the first - * name added to the ADDITIONAL section. dns_message_addname() - * performs an append on the list of names in a given section, - * so if any glue record was marked as required, we need to - * move the name it is associated with to the beginning of the - * list for the ADDITIONAL section or else required glue might - * not be rendered. - */ - if (prepend_name) { - ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL], - name, link); - ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL], - name, link); - } - } -} - -static dns_glue_t * -newglue(dns_qpdb_t *qpdb, dns_qpdb_version_t *rbtversion, dns_qpdata_t *node, - dns_rdataset_t *rdataset) { - dns_fixedname_t nodename; - dns_glue_additionaldata_ctx_t ctx = { - .db = (dns_db_t *)qpdb, - .version = (dns_dbversion_t *)rbtversion, - .nodename = dns_fixedname_initname(&nodename), - }; - - /* - * Get the owner name of the NS RRset - it will be necessary for - * identifying required glue in glue_nsdname_cb() (by - * determining which NS records in the delegation are - * in-bailiwick). - */ - dns__qpdb_nodefullname((dns_db_t *)qpdb, node, ctx.nodename); - - (void)dns_rdataset_additionaldata(rdataset, dns_rootname, - glue_nsdname_cb, &ctx); - - return (ctx.glue_list); -} - -static isc_result_t -addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset, - dns_message_t *msg) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdb_version_t *rbtversion = version; - dns_qpdata_t *node = (dns_qpdata_t *)rdataset->slab.node; - dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); - - REQUIRE(rdataset->type == dns_rdatatype_ns); - REQUIRE(qpdb == (dns_qpdb_t *)rdataset->slab.db); - REQUIRE(qpdb == rbtversion->qpdb); - REQUIRE(!IS_CACHE(qpdb) && !IS_STUB(qpdb)); - - rcu_read_lock(); - - dns_glue_t *glue = rcu_dereference(header->glue_list); - if (glue == NULL) { - /* No cached glue was found in the table. Get new glue. */ - glue = newglue(qpdb, rbtversion, node, rdataset); - - /* Cache the glue or (void *)-1 if no glue was found. */ - dns_glue_t *old_glue = rcu_cmpxchg_pointer( - &header->glue_list, NULL, (glue) ? glue : (void *)-1); - if (old_glue != NULL) { - /* Somebody else was faster */ - dns__qpdb_freeglue(glue); - glue = old_glue; - } else if (glue != NULL) { - cds_wfs_push(&rbtversion->glue_stack, - &header->wfs_node); - } - } - - /* We have a cached result. Add it to the message and return. */ - - if (qpdb->gluecachestats != NULL) { - isc_stats_increment( - qpdb->gluecachestats, - (glue == (void *)-1) - ? dns_gluecachestatscounter_hits_absent - : dns_gluecachestatscounter_hits_present); - } - - /* - * (void *)-1 is a special value that means no glue is present in the - * zone. - */ - if (glue != (void *)-1) { - addglue_to_message(glue, msg); - } - - rcu_read_unlock(); - - return (ISC_R_SUCCESS); -} - -dns_dbmethods_t dns__qpdb_zonemethods = { - .destroy = dns__qpdb_destroy, - .beginload = beginload, - .endload = endload, - .currentversion = dns__qpdb_currentversion, - .newversion = dns__qpdb_newversion, - .attachversion = dns__qpdb_attachversion, - .closeversion = dns__qpdb_closeversion, - .findnode = dns__qpdb_findnode, - .find = zone_find, - .attachnode = dns__qpdb_attachnode, - .detachnode = dns__qpdb_detachnode, - .createiterator = dns__qpdb_createiterator, - .findrdataset = zone_findrdataset, - .allrdatasets = dns__qpdb_allrdatasets, - .addrdataset = dns__qpdb_addrdataset, - .subtractrdataset = dns__qpdb_subtractrdataset, - .deleterdataset = dns__qpdb_deleterdataset, - .issecure = issecure, - .nodecount = dns__qpdb_nodecount, - .setloop = dns__qpdb_setloop, - .getoriginnode = dns__qpdb_getoriginnode, - .getnsec3parameters = getnsec3parameters, - .findnsec3node = findnsec3node, - .setsigningtime = setsigningtime, - .getsigningtime = getsigningtime, - .getsize = getsize, - .setgluecachestats = setgluecachestats, - .locknode = dns__qpdb_locknode, - .unlocknode = dns__qpdb_unlocknode, - .addglue = addglue, - .deletedata = dns__qpdb_deletedata, - .nodefullname = dns__qpdb_nodefullname, -}; - -void -dns__qpzone_resigninsert(dns_qpdb_t *qpdb, int idx, - dns_slabheader_t *newheader) { - INSIST(!IS_CACHE(qpdb)); - INSIST(newheader->heap_index == 0); - INSIST(!ISC_LINK_LINKED(newheader, link)); - - isc_heap_insert(qpdb->heaps[idx], newheader); - newheader->heap = qpdb->heaps[idx]; -} - -void -dns__qpzone_resigndelete(dns_qpdb_t *qpdb, dns_qpdb_version_t *version, - dns_slabheader_t *header DNS__DB_FLARG) { - /* - * Remove the old header from the heap - */ - if (header != NULL && header->heap_index != 0) { - isc_heap_delete(qpdb->heaps[QPDB_HEADERNODE(header)->locknum], - header->heap_index); - header->heap_index = 0; - if (version != NULL) { - dns__qpdb_newref( - qpdb, QPDB_HEADERNODE(header), - isc_rwlocktype_write DNS__DB_FLARG_PASS); - ISC_LIST_APPEND(version->resigned_list, header, link); - } - } -} - -isc_result_t -dns__qpzone_wildcardmagic(dns_qpdb_t *qpdb, const dns_name_t *name, bool lock) { - isc_result_t result; - dns_name_t foundname; - dns_offsets_t offsets; - unsigned int n; - dns_qpdata_t *node = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - dns_name_init(&foundname, offsets); - n = dns_name_countlabels(name); - INSIST(n >= 2); - n--; - dns_name_getlabelsequence(name, 1, n, &foundname); - - result = dns_qp_getname(qpdb->tree, &foundname, (void **)&node, NULL); - if (result != ISC_R_SUCCESS) { - INSIST(node == NULL); - node = dns_qpdata_create(qpdb, &foundname); - result = dns_qp_insert(qpdb->tree, node, 0); - INSIST(result == ISC_R_SUCCESS); - dns_qpdata_unref(node); - } - - INSIST(result == ISC_R_SUCCESS); - node->nsec = DNS_DB_NSEC_NORMAL; - node->find_callback = 1; - if (lock) { - NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); - } - node->wild = 1; - if (lock) { - NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); - } - return (ISC_R_SUCCESS); -} - -isc_result_t -dns__qpzone_addwildcards(dns_qpdb_t *qpdb, const dns_name_t *name, bool lock) { - isc_result_t result; - dns_name_t foundname; - dns_offsets_t offsets; - unsigned int n, l, i; - - dns_name_init(&foundname, offsets); - n = dns_name_countlabels(name); - l = dns_name_countlabels(&qpdb->common.origin); - i = l + 1; - while (i < n) { - dns_qpdata_t *node = NULL; - dns_name_getlabelsequence(name, n - i, i, &foundname); - if (dns_name_iswildcard(&foundname)) { - result = dns__qpzone_wildcardmagic(qpdb, &foundname, - lock); - if (result != ISC_R_SUCCESS) { - return (result); - } - - result = dns_qp_getname(qpdb->tree, name, - (void **)&node, NULL); - if (result != ISC_R_SUCCESS) { - INSIST(node == NULL); - node = dns_qpdata_create(qpdb, name); - node->nsec = DNS_DB_NSEC_NORMAL; - result = dns_qp_insert(qpdb->tree, node, 0); - INSIST(result == ISC_R_SUCCESS); - dns_qpdata_detach(&node); - } else if (result == ISC_R_SUCCESS) { - node->nsec = DNS_DB_NSEC_NORMAL; - } - } - i++; - } - return (ISC_R_SUCCESS); -} diff --git a/lib/dns/qpdb.c b/lib/dns/qpdb.c index 8ed465b182..38e479588b 100644 --- a/lib/dns/qpdb.c +++ b/lib/dns/qpdb.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include "db_p.h" @@ -90,9 +89,6 @@ #define STALE_WINDOW(header) \ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_STALE_WINDOW) != 0) -#define RESIGN(header) \ - ((atomic_load_acquire(&(header)->attributes) & \ - DNS_SLABHEADERATTR_RESIGN) != 0) #define OPTOUT(header) \ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_OPTOUT) != 0) @@ -207,9 +203,6 @@ qp_triename(void *uctx, char *buf, size_t size) { snprintf(buf, size, "qpdb-lite"); } -static void -free_gluetable(struct cds_wfs_stack *glue_stack); - static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG); static isc_result_t @@ -287,8 +280,6 @@ typedef struct qpdb_dbiterator { static void free_qpdb(dns_qpdb_t *qpdb, bool log); -static void -setnsec3parameters(dns_db_t *db, dns_qpdb_version_t *version); /*% * 'init_count' is used to initialize 'newheader->count' which inturn @@ -313,12 +304,6 @@ static atomic_uint_fast16_t init_count = 0; * Failure to follow this hierarchy can result in deadlock. */ -/* - * Deleting Nodes - * - * For zone databases the node for the origin of the zone MUST NOT be deleted. - */ - /* * DB Routines */ @@ -429,21 +414,6 @@ ttl_sooner(void *v1, void *v2) { return (h1->ttl < h2->ttl); } -/*% - * Return which RRset should be resigned sooner. If the RRsets have the - * same signing time, prefer the other RRset over the SOA RRset. - */ -static bool -resign_sooner(void *v1, void *v2) { - dns_slabheader_t *h1 = v1; - dns_slabheader_t *h2 = v2; - - return (h1->resign < h2->resign || - (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) || - (h1->resign == h2->resign && h1->resign_lsb == h2->resign_lsb && - h2->type == DNS_SIGTYPE(dns_rdatatype_soa))); -} - /*% * This function sets the heap index into the header. */ @@ -460,20 +430,6 @@ free_qpdb(dns_qpdb_t *qpdb, bool log) { char buf[DNS_NAME_FORMATSIZE]; dns_qp_t **treep = NULL; - REQUIRE(qpdb->current_version != NULL || EMPTY(qpdb->open_versions)); - REQUIRE(qpdb->future_version == NULL); - - if (qpdb->current_version != NULL) { - isc_refcount_decrementz(&qpdb->current_version->references); - - isc_refcount_destroy(&qpdb->current_version->references); - UNLINK(qpdb->open_versions, qpdb->current_version, link); - cds_wfs_destroy(&qpdb->current_version->glue_stack); - isc_rwlock_destroy(&qpdb->current_version->rwlock); - isc_mem_put(qpdb->common.mctx, qpdb->current_version, - sizeof(*qpdb->current_version)); - } - /* * We assume the number of remaining dead nodes is reasonably small; * the overhead of unlinking all nodes here should be negligible. @@ -615,15 +571,6 @@ dns__qpdb_destroy(dns_db_t *arg) { dns_db_detachnode((dns_db_t *)qpdb, &qpdb->nsnode); } - /* - * The current version's glue table needs to be freed early - * so the nodes are dereferenced before we check the active - * node count below. - */ - if (qpdb->current_version != NULL) { - free_gluetable(&qpdb->current_version->glue_stack); - } - /* * Even though there are no external direct references, there still * may be nodes in use. @@ -662,169 +609,6 @@ dns__qpdb_destroy(dns_db_t *arg) { } } -void -dns__qpdb_currentversion(dns_db_t *db, dns_dbversion_t **versionp) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdb_version_t *version = NULL; - - REQUIRE(VALID_QPDB(qpdb)); - - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - version = qpdb->current_version; - isc_refcount_increment(&version->references); - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - - *versionp = (dns_dbversion_t *)version; -} - -static dns_qpdb_version_t * -allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references, - bool writer) { - dns_qpdb_version_t *version = isc_mem_get(mctx, sizeof(*version)); - *version = (dns_qpdb_version_t){ - .serial = serial, - .writer = writer, - .changed_list = ISC_LIST_INITIALIZER, - .resigned_list = ISC_LIST_INITIALIZER, - .link = ISC_LINK_INITIALIZER, - }; - - cds_wfs_init(&version->glue_stack); - - isc_refcount_init(&version->references, references); - - return (version); -} - -isc_result_t -dns__qpdb_newversion(dns_db_t *db, dns_dbversion_t **versionp) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdb_version_t *version = NULL; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(versionp != NULL && *versionp == NULL); - REQUIRE(qpdb->future_version == NULL); - - RWLOCK(&qpdb->lock, isc_rwlocktype_write); - RUNTIME_CHECK(qpdb->next_serial != 0); /* XXX Error? */ - version = allocate_version(qpdb->common.mctx, qpdb->next_serial, 1, - true); - version->qpdb = qpdb; - version->commit_ok = true; - version->secure = qpdb->current_version->secure; - version->havensec3 = qpdb->current_version->havensec3; - if (version->havensec3) { - version->flags = qpdb->current_version->flags; - version->iterations = qpdb->current_version->iterations; - version->hash = qpdb->current_version->hash; - version->salt_length = qpdb->current_version->salt_length; - memmove(version->salt, qpdb->current_version->salt, - version->salt_length); - } else { - version->flags = 0; - version->iterations = 0; - version->hash = 0; - version->salt_length = 0; - memset(version->salt, 0, sizeof(version->salt)); - } - isc_rwlock_init(&version->rwlock); - RWLOCK(&qpdb->current_version->rwlock, isc_rwlocktype_read); - version->records = qpdb->current_version->records; - version->xfrsize = qpdb->current_version->xfrsize; - RWUNLOCK(&qpdb->current_version->rwlock, isc_rwlocktype_read); - qpdb->next_serial++; - qpdb->future_version = version; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - - *versionp = version; - - return (ISC_R_SUCCESS); -} - -void -dns__qpdb_attachversion(dns_db_t *db, dns_dbversion_t *source, - dns_dbversion_t **targetp) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdb_version_t *rbtversion = source; - - REQUIRE(VALID_QPDB(qpdb)); - INSIST(rbtversion != NULL && rbtversion->qpdb == qpdb); - - isc_refcount_increment(&rbtversion->references); - - *targetp = rbtversion; -} - -static qpdb_changed_t * -add_changed(dns_slabheader_t *header, - dns_qpdb_version_t *version DNS__DB_FLARG) { - qpdb_changed_t *changed = NULL; - dns_qpdb_t *qpdb = (dns_qpdb_t *)header->db; - - /* - * Caller must be holding the node lock if its reference must be - * protected by the lock. - */ - - changed = isc_mem_get(qpdb->common.mctx, sizeof(*changed)); - - RWLOCK(&qpdb->lock, isc_rwlocktype_write); - - REQUIRE(version->writer); - - if (changed != NULL) { - dns_qpdata_t *node = (dns_qpdata_t *)header->node; - - dns__qpdb_newref(qpdb, node, - isc_rwlocktype_none DNS__DB_FLARG_PASS); - - changed->node = node; - changed->dirty = false; - ISC_LIST_INITANDAPPEND(version->changed_list, changed, link); - } else { - version->commit_ok = false; - } - - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - - return (changed); -} - -static void -rollback_node(dns_qpdata_t *node, uint32_t serial) { - dns_slabheader_t *header = NULL, *dcurrent = NULL; - bool make_dirty = false; - - /* - * Caller must hold the node lock. - */ - - /* - * We set the IGNORE attribute on rdatasets with serial number - * 'serial'. When the reference count goes to zero, these rdatasets - * will be cleaned up; until that time, they will be ignored. - */ - for (header = node->data; header != NULL; header = header->next) { - if (header->serial == serial) { - DNS_SLABHEADER_SETATTR(header, - DNS_SLABHEADERATTR_IGNORE); - make_dirty = true; - } - for (dcurrent = header->down; dcurrent != NULL; - dcurrent = dcurrent->down) - { - if (dcurrent->serial == serial) { - DNS_SLABHEADER_SETATTR( - dcurrent, DNS_SLABHEADERATTR_IGNORE); - make_dirty = true; - } - } - } - if (make_dirty) { - node->dirty = 1; - } -} - void dns__qpdb_mark(dns_slabheader_t *header, uint_least16_t flag) { uint_least16_t attributes = atomic_load_acquire(&header->attributes); @@ -902,138 +686,6 @@ clean_cache_node(dns_qpdb_t *qpdb, dns_qpdata_t *node) { node->dirty = 0; } -static void -clean_zone_node(dns_qpdata_t *node, uint32_t least_serial) { - dns_slabheader_t *current = NULL, *dcurrent = NULL; - dns_slabheader_t *down_next = NULL, *dparent = NULL; - dns_slabheader_t *top_prev = NULL, *top_next = NULL; - bool still_dirty = false; - - /* - * Caller must be holding the node lock. - */ - REQUIRE(least_serial != 0); - - for (current = node->data; current != NULL; current = top_next) { - top_next = current->next; - - /* - * First, we clean up any instances of multiple rdatasets - * with the same serial number, or that have the IGNORE - * attribute. - */ - dparent = current; - for (dcurrent = current->down; dcurrent != NULL; - dcurrent = down_next) - { - down_next = dcurrent->down; - INSIST(dcurrent->serial <= dparent->serial); - if (dcurrent->serial == dparent->serial || - IGNORE(dcurrent)) - { - if (down_next != NULL) { - down_next->next = dparent; - } - dparent->down = down_next; - dns_slabheader_destroy(&dcurrent); - } else { - dparent = dcurrent; - } - } - - /* - * We've now eliminated all IGNORE datasets with the possible - * exception of current, which we now check. - */ - if (IGNORE(current)) { - down_next = current->down; - if (down_next == NULL) { - if (top_prev != NULL) { - top_prev->next = current->next; - } else { - node->data = current->next; - } - dns_slabheader_destroy(¤t); - /* - * current no longer exists, so we can - * just continue with the loop. - */ - continue; - } else { - /* - * Pull up current->down, making it the new - * current. - */ - if (top_prev != NULL) { - top_prev->next = down_next; - } else { - node->data = down_next; - } - down_next->next = top_next; - dns_slabheader_destroy(¤t); - current = down_next; - } - } - - /* - * We now try to find the first down node less than the - * least serial. - */ - dparent = current; - for (dcurrent = current->down; dcurrent != NULL; - dcurrent = down_next) - { - down_next = dcurrent->down; - if (dcurrent->serial < least_serial) { - break; - } - dparent = dcurrent; - } - - /* - * If there is a such an rdataset, delete it and any older - * versions. - */ - if (dcurrent != NULL) { - do { - down_next = dcurrent->down; - INSIST(dcurrent->serial <= least_serial); - dns_slabheader_destroy(&dcurrent); - dcurrent = down_next; - } while (dcurrent != NULL); - dparent->down = NULL; - } - - /* - * Note. The serial number of 'current' might be less than - * least_serial too, but we cannot delete it because it is - * the most recent version, unless it is a NONEXISTENT - * rdataset. - */ - if (current->down != NULL) { - still_dirty = true; - top_prev = current; - } else { - /* - * If this is a NONEXISTENT rdataset, we can delete it. - */ - if (NONEXISTENT(current)) { - if (top_prev != NULL) { - top_prev->next = current->next; - } else { - node->data = current->next; - } - dns_slabheader_destroy(¤t); - } else { - top_prev = current; - } - } - } - if (!still_dirty) { - node->dirty = 0; - } -} - /* * tree_lock(write) must be held. */ @@ -1246,6 +898,7 @@ dns__qpdb_decref(dns_qpdb_t *qpdb, dns_qpdata_t *node, uint32_t least_serial, REQUIRE(*nlocktypep != isc_rwlocktype_none); UNUSED(pruning); + UNUSED(least_serial); nodelock = &qpdb->node_locks[bucket]; @@ -1302,20 +955,7 @@ dns__qpdb_decref(dns_qpdb_t *qpdb, dns_qpdata_t *node, uint32_t least_serial, INSIST(refs == 1); if (node->dirty) { - if (IS_CACHE(qpdb)) { - clean_cache_node(qpdb, node); - } else { - if (least_serial == 0) { - /* - * Caller doesn't know the least serial. - * Get it. - */ - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - least_serial = qpdb->least_serial; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - } - clean_zone_node(node, least_serial); - } + clean_cache_node(qpdb, node); } /* @@ -1391,506 +1031,16 @@ restore_locks: return (no_reference); } -static void -make_least_version(dns_qpdb_t *qpdb, dns_qpdb_version_t *version, - qpdb_changedlist_t *cleanup_list) { - /* - * Caller must be holding the database lock. - */ - - qpdb->least_serial = version->serial; - *cleanup_list = version->changed_list; - ISC_LIST_INIT(version->changed_list); -} - -static void -cleanup_nondirty(dns_qpdb_version_t *version, - qpdb_changedlist_t *cleanup_list) { - qpdb_changed_t *changed = NULL, *next_changed = NULL; - - /* - * If the changed record is dirty, then - * an update created multiple versions of - * a given rdataset. We keep this list - * until we're the least open version, at - * which point it's safe to get rid of any - * older versions. - * - * If the changed record isn't dirty, then - * we don't need it anymore since we're - * committing and not rolling back. - * - * The caller must be holding the database lock. - */ - for (changed = HEAD(version->changed_list); changed != NULL; - changed = next_changed) - { - next_changed = NEXT(changed, link); - if (!changed->dirty) { - UNLINK(version->changed_list, changed, link); - APPEND(*cleanup_list, changed, link); - } - } -} - -void -dns__qpdb_setsecure(dns_db_t *db, dns_qpdb_version_t *version, - dns_dbnode_t *origin) { - dns_rdataset_t keyset; - dns_rdataset_t nsecset, signsecset; - bool haszonekey = false; - bool hasnsec = false; - isc_result_t result; - - dns_rdataset_init(&keyset); - result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey, - 0, 0, &keyset, NULL); - if (result == ISC_R_SUCCESS) { - result = dns_rdataset_first(&keyset); - while (result == ISC_R_SUCCESS) { - dns_rdata_t keyrdata = DNS_RDATA_INIT; - dns_rdataset_current(&keyset, &keyrdata); - if (dns_zonekey_iszonekey(&keyrdata)) { - haszonekey = true; - break; - } - result = dns_rdataset_next(&keyset); - } - dns_rdataset_disassociate(&keyset); - } - if (!haszonekey) { - version->secure = false; - version->havensec3 = false; - return; - } - - dns_rdataset_init(&nsecset); - dns_rdataset_init(&signsecset); - result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec, 0, - 0, &nsecset, &signsecset); - if (result == ISC_R_SUCCESS) { - if (dns_rdataset_isassociated(&signsecset)) { - hasnsec = true; - dns_rdataset_disassociate(&signsecset); - } - dns_rdataset_disassociate(&nsecset); - } - - setnsec3parameters(db, version); - - /* - * Do we have a valid NSEC/NSEC3 chain? - */ - if (version->havensec3 || hasnsec) { - version->secure = true; - } else { - version->secure = false; - } -} - -/*%< - * Walk the origin node looking for NSEC3PARAM records. - * Cache the nsec3 parameters. - */ -static void -setnsec3parameters(dns_db_t *db, dns_qpdb_version_t *version) { - dns_qpdata_t *node = NULL; - dns_rdata_nsec3param_t nsec3param; - dns_rdata_t rdata = DNS_RDATA_INIT; - isc_region_t region; - isc_result_t result; - dns_slabheader_t *header = NULL, *header_next = NULL; - unsigned char *raw; /* RDATASLAB */ - unsigned int count, length; - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); - version->havensec3 = false; - node = qpdb->origin_node; - NODE_RDLOCK(&(qpdb->node_locks[node->locknum].lock), &nlocktype); - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - do { - if (header->serial <= version->serial && - !IGNORE(header)) - { - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - - if (header != NULL && - (header->type == dns_rdatatype_nsec3param)) - { - /* - * Find A NSEC3PARAM with a supported algorithm. - */ - raw = dns_slabheader_raw(header); - count = raw[0] * 256 + raw[1]; /* count */ - raw += DNS_RDATASET_COUNT + DNS_RDATASET_LENGTH; - while (count-- > 0U) { - length = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; - region.base = raw; - region.length = length; - raw += length; - dns_rdata_fromregion( - &rdata, qpdb->common.rdclass, - dns_rdatatype_nsec3param, ®ion); - result = dns_rdata_tostruct(&rdata, &nsec3param, - NULL); - INSIST(result == ISC_R_SUCCESS); - dns_rdata_reset(&rdata); - - if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && - !dns_nsec3_supportedhash(nsec3param.hash)) - { - continue; - } - - if (nsec3param.flags != 0) { - continue; - } - - memmove(version->salt, nsec3param.salt, - nsec3param.salt_length); - version->hash = nsec3param.hash; - version->salt_length = nsec3param.salt_length; - version->iterations = nsec3param.iterations; - version->flags = nsec3param.flags; - version->havensec3 = true; - /* - * Look for a better algorithm than the - * unknown test algorithm. - */ - if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { - goto unlock; - } - } - } - } -unlock: - NODE_UNLOCK(&(qpdb->node_locks[node->locknum].lock), &nlocktype); - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); -} - -static void -cleanup_dead_nodes_callback(void *arg) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)arg; - bool again = false; - unsigned int locknum; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - TREE_WRLOCK(&qpdb->tree_lock, &tlocktype); - for (locknum = 0; locknum < qpdb->node_lock_count; locknum++) { - NODE_WRLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); - cleanup_dead_nodes(qpdb, locknum DNS__DB_FILELINE); - if (ISC_LIST_HEAD(qpdb->deadnodes[locknum]) != NULL) { - again = true; - } - NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); - } - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - if (again) { - isc_async_run(qpdb->loop, cleanup_dead_nodes_callback, qpdb); - } else { - dns_db_detach((dns_db_t **)&qpdb); - } -} - -void -dns__qpdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp, - bool commit DNS__DB_FLARG) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdb_version_t *version = NULL, *cleanup_version = NULL; - dns_qpdb_version_t *least_greater = NULL; - bool rollback = false; - qpdb_changedlist_t cleanup_list; - dns_slabheaderlist_t resigned_list; - qpdb_changed_t *changed = NULL, *next_changed = NULL; - uint32_t serial, least_serial; - dns_qpdata_t *qpnode = NULL; - dns_slabheader_t *header = NULL; - - REQUIRE(VALID_QPDB(qpdb)); - version = (dns_qpdb_version_t *)*versionp; - INSIST(version->qpdb == qpdb); - - ISC_LIST_INIT(cleanup_list); - ISC_LIST_INIT(resigned_list); - - if (isc_refcount_decrement(&version->references) > 1) { - /* typical and easy case first */ - if (commit) { - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - INSIST(!version->writer); - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - } - goto end; - } - - /* - * Update the zone's secure status in version before making - * it the current version. - */ - if (version->writer && commit && !IS_CACHE(qpdb)) { - dns__qpdb_setsecure(db, version, qpdb->origin_node); - } - - RWLOCK(&qpdb->lock, isc_rwlocktype_write); - serial = version->serial; - if (version->writer) { - if (commit) { - unsigned int cur_ref; - dns_qpdb_version_t *cur_version = NULL; - - INSIST(version->commit_ok); - INSIST(version == qpdb->future_version); - /* - * The current version is going to be replaced. - * Release the (likely last) reference to it from the - * DB itself and unlink it from the open list. - */ - cur_version = qpdb->current_version; - cur_ref = isc_refcount_decrement( - &cur_version->references); - if (cur_ref == 1) { - (void)isc_refcount_current( - &cur_version->references); - if (cur_version->serial == qpdb->least_serial) { - INSIST(EMPTY( - cur_version->changed_list)); - } - UNLINK(qpdb->open_versions, cur_version, link); - } - if (EMPTY(qpdb->open_versions)) { - /* - * We're going to become the least open - * version. - */ - make_least_version(qpdb, version, - &cleanup_list); - } else { - /* - * Some other open version is the - * least version. We can't cleanup - * records that were changed in this - * version because the older versions - * may still be in use by an open - * version. - * - * We can, however, discard the - * changed records for things that - * we've added that didn't exist in - * prior versions. - */ - cleanup_nondirty(version, &cleanup_list); - } - /* - * If the (soon to be former) current version - * isn't being used by anyone, we can clean - * it up. - */ - if (cur_ref == 1) { - cleanup_version = cur_version; - APPENDLIST(version->changed_list, - cleanup_version->changed_list, link); - } - /* - * Become the current version. - */ - version->writer = false; - qpdb->current_version = version; - qpdb->current_serial = version->serial; - qpdb->future_version = NULL; - - /* - * Keep the current version in the open list, and - * gain a reference for the DB itself (see the DB - * creation function below). This must be the only - * case where we need to increment the counter from - * zero and need to use isc_refcount_increment0(). - */ - INSIST(isc_refcount_increment0(&version->references) == - 0); - PREPEND(qpdb->open_versions, qpdb->current_version, - link); - resigned_list = version->resigned_list; - ISC_LIST_INIT(version->resigned_list); - } else { - /* - * We're rolling back this transaction. - */ - cleanup_list = version->changed_list; - ISC_LIST_INIT(version->changed_list); - resigned_list = version->resigned_list; - ISC_LIST_INIT(version->resigned_list); - rollback = true; - cleanup_version = version; - qpdb->future_version = NULL; - } - } else { - if (version != qpdb->current_version) { - /* - * There are no external or internal references - * to this version and it can be cleaned up. - */ - cleanup_version = version; - - /* - * Find the version with the least serial - * number greater than ours. - */ - least_greater = PREV(version, link); - if (least_greater == NULL) { - least_greater = qpdb->current_version; - } - - INSIST(version->serial < least_greater->serial); - /* - * Is this the least open version? - */ - if (version->serial == qpdb->least_serial) { - /* - * Yes. Install the new least open - * version. - */ - make_least_version(qpdb, least_greater, - &cleanup_list); - } else { - /* - * Add any unexecuted cleanups to - * those of the least greater version. - */ - APPENDLIST(least_greater->changed_list, - version->changed_list, link); - } - } else if (version->serial == qpdb->least_serial) { - INSIST(EMPTY(version->changed_list)); - } - UNLINK(qpdb->open_versions, version, link); - } - least_serial = qpdb->least_serial; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); - - if (cleanup_version != NULL) { - isc_refcount_destroy(&cleanup_version->references); - INSIST(EMPTY(cleanup_version->changed_list)); - free_gluetable(&cleanup_version->glue_stack); - cds_wfs_destroy(&cleanup_version->glue_stack); - isc_rwlock_destroy(&cleanup_version->rwlock); - isc_mem_put(qpdb->common.mctx, cleanup_version, - sizeof(*cleanup_version)); - } - - /* - * Commit/rollback re-signed headers. - */ - for (header = HEAD(resigned_list); header != NULL; - header = HEAD(resigned_list)) - { - isc_rwlock_t *lock = NULL; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - ISC_LIST_UNLINK(resigned_list, header, link); - - lock = &qpdb->node_locks[QPDB_HEADERNODE(header)->locknum].lock; - NODE_WRLOCK(lock, &nlocktype); - if (rollback && !IGNORE(header)) { - dns__qpzone_resigninsert( - qpdb, QPDB_HEADERNODE(header)->locknum, header); - } - dns__qpdb_decref(qpdb, QPDB_HEADERNODE(header), least_serial, - &nlocktype, &tlocktype, true, - false DNS__DB_FLARG_PASS); - NODE_UNLOCK(lock, &nlocktype); - INSIST(tlocktype == isc_rwlocktype_none); - } - - if (!EMPTY(cleanup_list)) { - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - - if (qpdb->loop == NULL) { - /* - * We acquire a tree write lock here in order to make - * sure that stale nodes will be removed in - * dns__qpdb_decref(). If we didn't have the lock, - * those nodes could miss the chance to be removed - * until the server stops. The write lock is - * expensive, but this should be rare enough - * to justify the cost. - */ - TREE_WRLOCK(&qpdb->tree_lock, &tlocktype); - } - - for (changed = HEAD(cleanup_list); changed != NULL; - changed = next_changed) - { - isc_rwlock_t *lock = NULL; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - next_changed = NEXT(changed, link); - qpnode = changed->node; - lock = &qpdb->node_locks[qpnode->locknum].lock; - - NODE_WRLOCK(lock, &nlocktype); - /* - * This is a good opportunity to purge any dead nodes, - * so use it. - */ - if (qpdb->loop == NULL) { - cleanup_dead_nodes( - qpdb, - qpnode->locknum DNS__DB_FLARG_PASS); - } - - if (rollback) { - rollback_node(qpnode, serial); - } - dns__qpdb_decref(qpdb, qpnode, least_serial, &nlocktype, - &tlocktype, true, - false DNS__DB_FILELINE); - - NODE_UNLOCK(lock, &nlocktype); - - isc_mem_put(qpdb->common.mctx, changed, - sizeof(*changed)); - } - if (qpdb->loop != NULL) { - isc_refcount_increment(&qpdb->common.references); - isc_async_run(qpdb->loop, cleanup_dead_nodes_callback, - qpdb); - } else { - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - } - - INSIST(tlocktype == isc_rwlocktype_none); - } - -end: - *versionp = NULL; -} - isc_result_t dns__qpdb_findnodeintree(dns_qpdb_t *qpdb, dns_qp_t *tree, const dns_name_t *name, bool create, dns_dbnode_t **nodep DNS__DB_FLARG) { dns_qpdata_t *node = NULL; - dns_name_t nodename; isc_result_t result; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - INSIST(tree == qpdb->tree || tree == qpdb->nsec3); + REQUIRE(tree == qpdb->tree || tree == qpdb->nsec3); - dns_name_init(&nodename, NULL); TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); result = dns_qp_lookup(tree, name, NULL, NULL, NULL, (void **)&node, NULL); @@ -1914,17 +1064,6 @@ dns__qpdb_findnodeintree(dns_qpdb_t *qpdb, dns_qp_t *tree, dns_qpdata_unref(node); } - if (tree == qpdb->tree) { - dns__qpzone_addwildcards(qpdb, name, true); - - if (dns_name_iswildcard(name)) { - result = dns__qpzone_wildcardmagic(qpdb, name, - true); - if (result != ISC_R_SUCCESS) { - goto unlock; - } - } - } if (tree == qpdb->nsec3) { node->nsec = DNS_DB_NSEC_NSEC3; } @@ -2007,6 +1146,7 @@ dns__qpdb_bindrdataset(dns_qpdb_t *qpdb, dns_qpdata_t *node, rdataset->covers = DNS_TYPEPAIR_COVERS(header->type); rdataset->ttl = header->ttl - now; rdataset->trust = header->trust; + rdataset->resign = 0; if (NEGATIVE(header)) { rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE; @@ -2032,7 +1172,7 @@ dns__qpdb_bindrdataset(dns_qpdb_t *qpdb, dns_qpdata_t *node, rdataset->attributes |= DNS_RDATASETATTR_STALE_WINDOW; } rdataset->attributes |= DNS_RDATASETATTR_STALE; - } else if (IS_CACHE(qpdb) && !ACTIVE(header, now)) { + } else if (!ACTIVE(header, now)) { rdataset->attributes |= DNS_RDATASETATTR_ANCIENT; rdataset->ttl = header->ttl; } @@ -2056,16 +1196,6 @@ dns__qpdb_bindrdataset(dns_qpdb_t *qpdb, dns_qpdata_t *node, if (header->closest != NULL) { rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; } - - /* - * Copy out re-signing information. - */ - if (RESIGN(header)) { - rdataset->attributes |= DNS_RDATASETATTR_RESIGN; - rdataset->resign = (header->resign << 1) | header->resign_lsb; - } else { - rdataset->resign = 0; - } } void @@ -2190,35 +1320,23 @@ dns__qpdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { dns_qpdb_t *qpdb = (dns_qpdb_t *)db; dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - dns_qpdb_version_t *rbtversion = version; qpdb_rdatasetiter_t *iterator = NULL; REQUIRE(VALID_QPDB(qpdb)); + UNUSED(version); + iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator)); - if ((db->attributes & DNS_DBATTR_CACHE) == 0) { - now = 0; - if (rbtversion == NULL) { - dns__qpdb_currentversion( - db, (dns_dbversion_t **)(void *)(&rbtversion)); - } else { - INSIST(rbtversion->qpdb == qpdb); - - (void)isc_refcount_increment(&rbtversion->references); - } - } else { - if (now == 0) { - now = isc_stdtime_now(); - } - rbtversion = NULL; + if (now == 0) { + now = isc_stdtime_now(); } iterator->common.magic = DNS_RDATASETITER_MAGIC; iterator->common.methods = &rdatasetiter_methods; iterator->common.db = db; iterator->common.node = node; - iterator->common.version = (dns_dbversion_t *)rbtversion; + iterator->common.version = NULL; iterator->common.options = options; iterator->common.now = now; iterator->current = NULL; @@ -2230,168 +1348,30 @@ dns__qpdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, return (ISC_R_SUCCESS); } -static bool -cname_and_other_data(dns_qpdata_t *node, uint32_t serial) { - dns_slabheader_t *header = NULL, *header_next = NULL; - bool cname = false, other_data = false; - dns_rdatatype_t rdtype; - - /* - * The caller must hold the node lock. - */ - - /* - * Look for CNAME and "other data" rdatasets active in our version. - */ - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (!prio_type(header->type)) { - /* - * CNAME is in the priority list, so if we are done - * with the priority list, we know there will not be - * CNAME, so we are safe to skip the rest of the types. - */ - return (false); - } - if (header->type == dns_rdatatype_cname) { - /* - * Look for an active extant CNAME. - */ - do { - if (header->serial <= serial && !IGNORE(header)) - { - /* - * Is this a "this rdataset doesn't - * exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - cname = true; - } - } else { - /* - * Look for active extant "other data". - * - * "Other data" is any rdataset whose type is not - * KEY, NSEC, SIG or RRSIG. - */ - rdtype = DNS_TYPEPAIR_TYPE(header->type); - if (rdtype != dns_rdatatype_key && - rdtype != dns_rdatatype_sig && - rdtype != dns_rdatatype_nsec && - rdtype != dns_rdatatype_rrsig) - { - /* - * Is it active and extant? - */ - do { - if (header->serial <= serial && - !IGNORE(header)) - { - /* - * Is this a "this rdataset - * doesn't exist" record? - */ - if (NONEXISTENT(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - other_data = true; - } - } - } - if (cname && other_data) { - return (true); - } - } - - return (false); -} - -static uint64_t -recordsize(dns_slabheader_t *header, unsigned int namelen) { - return (dns_rdataslab_rdatasize((unsigned char *)header, - sizeof(*header)) + - sizeof(dns_ttl_t) + sizeof(dns_rdatatype_t) + - sizeof(dns_rdataclass_t) + namelen); -} - -static void -update_recordsandxfrsize(bool add, dns_qpdb_version_t *rbtversion, - dns_slabheader_t *header, unsigned int namelen) { - unsigned char *hdr = (unsigned char *)header; - size_t hdrsize = sizeof(*header); - - RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write); - if (add) { - rbtversion->records += dns_rdataslab_count(hdr, hdrsize); - rbtversion->xfrsize += recordsize(header, namelen); - } else { - rbtversion->records -= dns_rdataslab_count(hdr, hdrsize); - rbtversion->xfrsize -= recordsize(header, namelen); - } - RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write); -} - isc_result_t dns__qpdb_add(dns_qpdb_t *qpdb, dns_qpdata_t *qpnode, - const dns_name_t *nodename, dns_qpdb_version_t *rbtversion, + const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader, unsigned int options, bool loading, dns_rdataset_t *addedrdataset, isc_stdtime_t now DNS__DB_FLARG) { qpdb_changed_t *changed = NULL; dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; dns_slabheader_t *header = NULL, *sigheader = NULL; dns_slabheader_t *prioheader = NULL; - unsigned char *merged = NULL; - isc_result_t result; bool header_nx; bool newheader_nx; - bool merge; dns_rdatatype_t rdtype, covers; dns_typepair_t negtype = 0, sigtype; dns_trust_t trust; int idx; - if ((options & DNS_DBADD_MERGE) != 0) { - REQUIRE(rbtversion != NULL); - merge = true; - } else { - merge = false; - } - if ((options & DNS_DBADD_FORCE) != 0) { trust = dns_trust_ultimate; } else { trust = newheader->trust; } - if (rbtversion != NULL && !loading) { - /* - * We always add a changed record, even if no changes end up - * being made to this node, because it's harmless and - * simplifies the code. - */ - changed = add_changed(newheader, rbtversion DNS__DB_FLARG_PASS); - if (changed == NULL) { - dns_slabheader_destroy(&newheader); - return (ISC_R_NOMEMORY); - } - } - newheader_nx = NONEXISTENT(newheader) ? true : false; - if (rbtversion == NULL && !newheader_nx) { + if (!newheader_nx) { rdtype = DNS_TYPEPAIR_TYPE(newheader->type); covers = DNS_TYPEPAIR_COVERS(newheader->type); sigtype = DNS_SIGTYPE(covers); @@ -2525,8 +1505,7 @@ find_header: * data will supersede it below. Unclear what the best * policy is here. */ - if (rbtversion == NULL && trust < header->trust && - (ACTIVE(header, now) || header_nx)) + if (trust < header->trust && (ACTIVE(header, now) || header_nx)) { dns_slabheader_destroy(&newheader); if (addedrdataset != NULL) { @@ -2538,74 +1517,6 @@ find_header: return (DNS_R_UNCHANGED); } - /* - * Don't merge if a nonexistent rdataset is involved. - */ - if (merge && (header_nx || newheader_nx)) { - merge = false; - } - - /* - * If 'merge' is true, we'll try to create a new rdataset - * that is the union of 'newheader' and 'header'. - */ - if (merge) { - unsigned int flags = 0; - INSIST(rbtversion->serial >= header->serial); - merged = NULL; - result = ISC_R_SUCCESS; - - if ((options & DNS_DBADD_EXACT) != 0) { - flags |= DNS_RDATASLAB_EXACT; - } - /* - * TTL use here is irrelevant to the cache; - * merge is only done with zonedbs. - */ - if ((options & DNS_DBADD_EXACTTTL) != 0 && - newheader->ttl != header->ttl) - { - result = DNS_R_NOTEXACT; - } else if (newheader->ttl != header->ttl) { - flags |= DNS_RDATASLAB_FORCE; - } - if (result == ISC_R_SUCCESS) { - result = dns_rdataslab_merge( - (unsigned char *)header, - (unsigned char *)newheader, - (unsigned int)(sizeof(*newheader)), - qpdb->common.mctx, qpdb->common.rdclass, - (dns_rdatatype_t)header->type, flags, - &merged); - } - if (result == ISC_R_SUCCESS) { - /* - * If 'header' has the same serial number as - * we do, we could clean it up now if we knew - * that our caller had no references to it. - * We don't know this, however, so we leave it - * alone. It will get cleaned up when - * clean_zone_node() runs. - */ - dns_slabheader_destroy(&newheader); - newheader = (dns_slabheader_t *)merged; - dns_slabheader_reset(newheader, - (dns_db_t *)qpdb, - (dns_dbnode_t *)qpnode); - dns_slabheader_copycase(newheader, header); - if (loading && RESIGN(newheader) && - RESIGN(header) && - resign_sooner(header, newheader)) - { - newheader->resign = header->resign; - newheader->resign_lsb = - header->resign_lsb; - } - } else { - dns_slabheader_destroy(&newheader); - return (result); - } - } /* * Don't replace existing NS, A and AAAA RRsets in the * cache if they are already exist. This prevents named @@ -2614,9 +1525,9 @@ find_header: * special to be done w.r.t stale data; it gets replaced * normally further down. */ - if (IS_CACHE(qpdb) && ACTIVE(header, now) && - header->type == dns_rdatatype_ns && !header_nx && - !newheader_nx && header->trust >= newheader->trust && + if (ACTIVE(header, now) && header->type == dns_rdatatype_ns && + !header_nx && !newheader_nx && + header->trust >= newheader->trust && dns_rdataslab_equalx((unsigned char *)header, (unsigned char *)newheader, (unsigned int)(sizeof(*newheader)), @@ -2668,15 +1579,15 @@ find_header: * to be no more than the current NS RRset's TTL. This * ensures the delegations that are withdrawn are honoured. */ - if (IS_CACHE(qpdb) && ACTIVE(header, now) && - header->type == dns_rdatatype_ns && !header_nx && - !newheader_nx && header->trust <= newheader->trust) + if (ACTIVE(header, now) && header->type == dns_rdatatype_ns && + !header_nx && !newheader_nx && + header->trust <= newheader->trust) { if (newheader->ttl > header->ttl) { newheader->ttl = header->ttl; } } - if (IS_CACHE(qpdb) && ACTIVE(header, now) && + if (ACTIVE(header, now) && (options & DNS_DBADD_PREFETCH) == 0 && (header->type == dns_rdatatype_a || header->type == dns_rdatatype_aaaa || @@ -2727,32 +1638,21 @@ find_header: } return (ISC_R_SUCCESS); } - INSIST(rbtversion == NULL || - rbtversion->serial >= topheader->serial); + if (loading) { newheader->down = NULL; idx = QPDB_HEADERNODE(newheader)->locknum; - if (IS_CACHE(qpdb)) { - if (ZEROTTL(newheader)) { - newheader->last_used = qpdb->last_used + - 1; - ISC_LIST_APPEND(qpdb->lru[idx], - newheader, link); - } else { - ISC_LIST_PREPEND(qpdb->lru[idx], - newheader, link); - } - INSIST(qpdb->heaps != NULL); - isc_heap_insert(qpdb->heaps[idx], newheader); - newheader->heap = qpdb->heaps[idx]; - } else if (RESIGN(newheader)) { - dns__qpzone_resigninsert(qpdb, idx, newheader); - /* - * Don't call resigndelete, we don't need - * to reverse the delete. The free_slabheader - * call below will clean up the heap entry. - */ + if (ZEROTTL(newheader)) { + newheader->last_used = qpdb->last_used + 1; + ISC_LIST_APPEND(qpdb->lru[idx], newheader, + link); + } else { + ISC_LIST_PREPEND(qpdb->lru[idx], newheader, + link); } + INSIST(qpdb->heaps != NULL); + isc_heap_insert(qpdb->heaps[idx], newheader); + newheader->heap = qpdb->heaps[idx]; /* * There are no other references to 'header' when @@ -2766,32 +1666,19 @@ find_header: qpnode->data = newheader; } newheader->next = topheader->next; - if (rbtversion != NULL && !header_nx) { - update_recordsandxfrsize(false, rbtversion, - header, - nodename->length); - } dns_slabheader_destroy(&header); } else { idx = QPDB_HEADERNODE(newheader)->locknum; - if (IS_CACHE(qpdb)) { - INSIST(qpdb->heaps != NULL); - isc_heap_insert(qpdb->heaps[idx], newheader); - newheader->heap = qpdb->heaps[idx]; - if (ZEROTTL(newheader)) { - newheader->last_used = qpdb->last_used + - 1; - ISC_LIST_APPEND(qpdb->lru[idx], - newheader, link); - } else { - ISC_LIST_PREPEND(qpdb->lru[idx], - newheader, link); - } - } else if (RESIGN(newheader)) { - dns__qpzone_resigninsert(qpdb, idx, newheader); - dns__qpzone_resigndelete( - qpdb, rbtversion, - header DNS__DB_FLARG_PASS); + INSIST(qpdb->heaps != NULL); + isc_heap_insert(qpdb->heaps[idx], newheader); + newheader->heap = qpdb->heaps[idx]; + if (ZEROTTL(newheader)) { + newheader->last_used = qpdb->last_used + 1; + ISC_LIST_APPEND(qpdb->lru[idx], newheader, + link); + } else { + ISC_LIST_PREPEND(qpdb->lru[idx], newheader, + link); } if (topheader_prev != NULL) { topheader_prev->next = newheader; @@ -2805,16 +1692,9 @@ find_header: if (changed != NULL) { changed->dirty = true; } - if (rbtversion == NULL) { - mark_ancient(header); - if (sigheader != NULL) { - mark_ancient(sigheader); - } - } - if (rbtversion != NULL && !header_nx) { - update_recordsandxfrsize(false, rbtversion, - header, - nodename->length); + mark_ancient(header); + if (sigheader != NULL) { + mark_ancient(sigheader); } } } else { @@ -2832,20 +1712,12 @@ find_header: } idx = QPDB_HEADERNODE(newheader)->locknum; - if (IS_CACHE(qpdb)) { - isc_heap_insert(qpdb->heaps[idx], newheader); - newheader->heap = qpdb->heaps[idx]; - if (ZEROTTL(newheader)) { - ISC_LIST_APPEND(qpdb->lru[idx], newheader, - link); - } else { - ISC_LIST_PREPEND(qpdb->lru[idx], newheader, - link); - } - } else if (RESIGN(newheader)) { - dns__qpzone_resigninsert(qpdb, idx, newheader); - dns__qpzone_resigndelete(qpdb, rbtversion, - header DNS__DB_FLARG_PASS); + isc_heap_insert(qpdb->heaps[idx], newheader); + newheader->heap = qpdb->heaps[idx]; + if (ZEROTTL(newheader)) { + ISC_LIST_APPEND(qpdb->lru[idx], newheader, link); + } else { + ISC_LIST_PREPEND(qpdb->lru[idx], newheader, link); } if (topheader != NULL) { @@ -2858,8 +1730,6 @@ find_header: * we INSIST on it. */ INSIST(!loading); - INSIST(rbtversion == NULL || - rbtversion->serial >= topheader->serial); if (topheader_prev != NULL) { topheader_prev->next = newheader; } else { @@ -2894,20 +1764,6 @@ find_header: } } - if (rbtversion != NULL && !newheader_nx) { - update_recordsandxfrsize(true, rbtversion, newheader, - nodename->length); - } - - /* - * Check if the node now contains CNAME and other data. - */ - if (rbtversion != NULL && - cname_and_other_data(qpnode, rbtversion->serial)) - { - return (DNS_R_CNAMEANDOTHER); - } - if (addedrdataset != NULL) { dns__qpdb_bindrdataset(qpdb, qpnode, newheader, now, isc_rwlocktype_write, @@ -2917,23 +1773,6 @@ find_header: return (ISC_R_SUCCESS); } -static bool -delegating_type(dns_qpdb_t *qpdb, dns_qpdata_t *node, dns_typepair_t type) { - if (IS_CACHE(qpdb)) { - if (type == dns_rdatatype_dname) { - return (true); - } else { - return (false); - } - } else if (type == dns_rdatatype_dname || - (type == dns_rdatatype_ns && - (node != qpdb->origin_node || IS_STUB(qpdb)))) - { - return (true); - } - return (false); -} - static isc_result_t addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, dns_rdataset_t *rdataset) { @@ -3023,11 +1862,10 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_rdataset_t *addedrdataset DNS__DB_FLARG) { dns_qpdb_t *qpdb = (dns_qpdb_t *)db; dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - dns_qpdb_version_t *rbtversion = version; isc_region_t region; dns_slabheader_t *newheader = NULL; isc_result_t result; - bool delegating; + bool delegating = false; bool newnsec; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; @@ -3036,33 +1874,10 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name = NULL; REQUIRE(VALID_QPDB(qpdb)); - INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb); + REQUIRE(version == NULL); - if (!IS_CACHE(qpdb)) { - /* - * SOA records are only allowed at top of zone. - */ - if (rdataset->type == dns_rdatatype_soa && - node != qpdb->origin_node) - { - return (DNS_R_NOTZONETOP); - } - TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); - REQUIRE(((qpnode->nsec == DNS_DB_NSEC_NSEC3 && - (rdataset->type == dns_rdatatype_nsec3 || - rdataset->covers == dns_rdatatype_nsec3)) || - (qpnode->nsec != DNS_DB_NSEC_NSEC3 && - rdataset->type != dns_rdatatype_nsec3 && - rdataset->covers != dns_rdatatype_nsec3))); - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - } - - if (rbtversion == NULL) { - if (now == 0) { - now = isc_stdtime_now(); - } - } else { - now = 0; + if (now == 0) { + now = isc_stdtime_now(); } result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, @@ -3072,7 +1887,7 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, } name = dns_fixedname_initname(&fixed); - dns__qpdb_nodefullname(db, node, name); + dns_name_copy(qpnode->name, name); dns_rdataset_getownercase(rdataset, name); newheader = (dns_slabheader_t *)region.base; @@ -3090,64 +1905,41 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, } atomic_init(&newheader->count, atomic_fetch_add_relaxed(&init_count, 1)); - if (rbtversion != NULL) { - newheader->serial = rbtversion->serial; - now = 0; - - if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { - DNS_SLABHEADER_SETATTR(newheader, - DNS_SLABHEADERATTR_RESIGN); - newheader->resign = - (isc_stdtime_t)(dns_time64_from32( - rdataset->resign) >> - 1); - newheader->resign_lsb = rdataset->resign & 0x1; + newheader->serial = 1; + if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0) { + DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_PREFETCH); + } + if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { + DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NEGATIVE); + } + if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) { + DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NXDOMAIN); + } + if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0) { + DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_OPTOUT); + } + if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) { + result = addnoqname(qpdb->common.mctx, newheader, rdataset); + if (result != ISC_R_SUCCESS) { + dns_slabheader_destroy(&newheader); + return (result); } - } else { - newheader->serial = 1; - if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0) { - DNS_SLABHEADER_SETATTR(newheader, - DNS_SLABHEADERATTR_PREFETCH); - } - if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { - DNS_SLABHEADER_SETATTR(newheader, - DNS_SLABHEADERATTR_NEGATIVE); - } - if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) { - DNS_SLABHEADER_SETATTR(newheader, - DNS_SLABHEADERATTR_NXDOMAIN); - } - if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0) { - DNS_SLABHEADER_SETATTR(newheader, - DNS_SLABHEADERATTR_OPTOUT); - } - if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) { - result = addnoqname(qpdb->common.mctx, newheader, - rdataset); - if (result != ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); - return (result); - } - } - if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { - result = addclosest(qpdb->common.mctx, newheader, - rdataset); - if (result != ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); - return (result); - } + } + if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { + result = addclosest(qpdb->common.mctx, newheader, rdataset); + if (result != ISC_R_SUCCESS) { + dns_slabheader_destroy(&newheader); + return (result); } } /* - * If we're adding a delegation type (e.g. NS or DNAME for a zone, - * just DNAME for the cache), then we need to set the callback bit - * on the node. + * If we're adding a delegation type (which would be an NS or DNAME + * for a zone, but only DNAME counts for a cache), we need to set + * the callback bit on the node. */ - if (delegating_type(qpdb, qpnode, rdataset->type)) { + if (rdataset->type == dns_rdatatype_dname) { delegating = true; - } else { - delegating = false; } /* @@ -3170,7 +1962,7 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, * not necessarily have to be acquired but it will help purge * ancient entries more effectively. */ - if (IS_CACHE(qpdb) && isc_mem_isovermem(qpdb->common.mctx)) { + if (isc_mem_isovermem(qpdb->common.mctx)) { cache_is_overmem = true; } if (delegating || newnsec || cache_is_overmem) { @@ -3191,25 +1983,20 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, true); } - if (IS_CACHE(qpdb)) { - if (tlocktype == isc_rwlocktype_write) { - cleanup_dead_nodes(qpdb, - qpnode->locknum DNS__DB_FLARG_PASS); - } + if (tlocktype == isc_rwlocktype_write) { + cleanup_dead_nodes(qpdb, qpnode->locknum DNS__DB_FLARG_PASS); + } - expire_ttl_headers(qpdb, qpnode->locknum, &tlocktype, now, - cache_is_overmem DNS__DB_FLARG_PASS); + expire_ttl_headers(qpdb, qpnode->locknum, &tlocktype, now, + cache_is_overmem DNS__DB_FLARG_PASS); - /* - * If we've been holding a write lock on the tree just for - * cleaning, we can release it now. However, we still need the - * node lock. - */ - if (tlocktype == isc_rwlocktype_write && !delegating && - !newnsec) - { - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - } + /* + * If we've been holding a write lock on the tree just for + * cleaning, we can release it now. However, we still need the + * node lock. + */ + if (tlocktype == isc_rwlocktype_write && !delegating && !newnsec) { + TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); } result = ISC_R_SUCCESS; @@ -3232,8 +2019,8 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, } if (result == ISC_R_SUCCESS) { - result = dns__qpdb_add(qpdb, qpnode, name, rbtversion, - newheader, options, false, addedrdataset, + result = dns__qpdb_add(qpdb, qpnode, name, newheader, options, + false, addedrdataset, now DNS__DB_FLARG_PASS); } if (result == ISC_R_SUCCESS && delegating) { @@ -3247,233 +2034,6 @@ dns__qpdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, } INSIST(tlocktype == isc_rwlocktype_none); - /* - * Update the zone's secure status. If version is non-NULL - * this is deferred until dns__qpdb_closeversion() is called. - */ - if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(qpdb)) { - dns__qpdb_setsecure(db, version, qpdb->origin_node); - } - - return (result); -} - -isc_result_t -dns__qpdb_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, - dns_dbversion_t *version, dns_rdataset_t *rdataset, - unsigned int options, - dns_rdataset_t *newrdataset DNS__DB_FLARG) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - dns_qpdb_version_t *rbtversion = version; - dns_fixedname_t fname; - dns_name_t *nodename = dns_fixedname_initname(&fname); - dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; - dns_slabheader_t *header = NULL, *newheader = NULL; - unsigned char *subresult = NULL; - isc_region_t region; - isc_result_t result; - qpdb_changed_t *changed = NULL; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(rbtversion != NULL && rbtversion->qpdb == qpdb); - - if (!IS_CACHE(qpdb)) { - TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); - REQUIRE(((qpnode->nsec == DNS_DB_NSEC_NSEC3 && - (rdataset->type == dns_rdatatype_nsec3 || - rdataset->covers == dns_rdatatype_nsec3)) || - (qpnode->nsec != DNS_DB_NSEC_NSEC3 && - rdataset->type != dns_rdatatype_nsec3 && - rdataset->covers != dns_rdatatype_nsec3))); - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - } - - dns__qpdb_nodefullname(db, node, nodename); - - result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, - ®ion, sizeof(dns_slabheader_t)); - if (result != ISC_R_SUCCESS) { - return (result); - } - - newheader = (dns_slabheader_t *)region.base; - dns_slabheader_reset(newheader, db, node); - dns__qpdb_setttl(newheader, rdataset->ttl); - newheader->type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers); - atomic_init(&newheader->attributes, 0); - newheader->serial = rbtversion->serial; - newheader->trust = 0; - newheader->noqname = NULL; - newheader->closest = NULL; - atomic_init(&newheader->count, - atomic_fetch_add_relaxed(&init_count, 1)); - newheader->last_used = 0; - newheader->node = qpnode; - newheader->db = (dns_db_t *)qpdb; - if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); - newheader->resign = - (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> - 1); - newheader->resign_lsb = rdataset->resign & 0x1; - } else { - newheader->resign = 0; - newheader->resign_lsb = 0; - } - - NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - - changed = add_changed(newheader, rbtversion DNS__DB_FLARG_PASS); - if (changed == NULL) { - dns_slabheader_destroy(&newheader); - NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, - &nlocktype); - return (ISC_R_NOMEMORY); - } - - for (topheader = qpnode->data; topheader != NULL; - topheader = topheader->next) - { - if (topheader->type == newheader->type) { - break; - } - topheader_prev = topheader; - } - /* - * If header isn't NULL, we've found the right type. There may be - * IGNORE rdatasets between the top of the chain and the first real - * data. We skip over them. - */ - header = topheader; - while (header != NULL && IGNORE(header)) { - header = header->down; - } - if (header != NULL && EXISTS(header)) { - unsigned int flags = 0; - subresult = NULL; - result = ISC_R_SUCCESS; - if ((options & DNS_DBSUB_EXACT) != 0) { - flags |= DNS_RDATASLAB_EXACT; - if (newheader->ttl != header->ttl) { - result = DNS_R_NOTEXACT; - } - } - if (result == ISC_R_SUCCESS) { - result = dns_rdataslab_subtract( - (unsigned char *)header, - (unsigned char *)newheader, - (unsigned int)(sizeof(*newheader)), - qpdb->common.mctx, qpdb->common.rdclass, - (dns_rdatatype_t)header->type, flags, - &subresult); - } - if (result == ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); - newheader = (dns_slabheader_t *)subresult; - dns_slabheader_reset(newheader, db, node); - dns_slabheader_copycase(newheader, header); - if (RESIGN(header)) { - DNS_SLABHEADER_SETATTR( - newheader, DNS_SLABHEADERATTR_RESIGN); - newheader->resign = header->resign; - newheader->resign_lsb = header->resign_lsb; - dns__qpzone_resigninsert(qpdb, qpnode->locknum, - newheader); - } - /* - * We have to set the serial since the rdataslab - * subtraction routine copies the reserved portion of - * header, not newheader. - */ - newheader->serial = rbtversion->serial; - /* - * XXXJT: dns_rdataslab_subtract() copied the pointers - * to additional info. We need to clear these fields - * to avoid having duplicated references. - */ - update_recordsandxfrsize(true, rbtversion, newheader, - nodename->length); - } else if (result == DNS_R_NXRRSET) { - /* - * This subtraction would remove all of the rdata; - * add a nonexistent header instead. - */ - dns_slabheader_destroy(&newheader); - newheader = dns_slabheader_new((dns_db_t *)qpdb, - (dns_dbnode_t *)qpnode); - dns__qpdb_setttl(newheader, 0); - newheader->type = topheader->type; - atomic_init(&newheader->attributes, - DNS_SLABHEADERATTR_NONEXISTENT); - newheader->serial = rbtversion->serial; - } else { - dns_slabheader_destroy(&newheader); - goto unlock; - } - - /* - * If we're here, we want to link newheader in front of - * topheader. - */ - INSIST(rbtversion->serial >= topheader->serial); - update_recordsandxfrsize(false, rbtversion, header, - nodename->length); - if (topheader_prev != NULL) { - topheader_prev->next = newheader; - } else { - qpnode->data = newheader; - } - newheader->next = topheader->next; - newheader->down = topheader; - topheader->next = newheader; - qpnode->dirty = 1; - changed->dirty = true; - dns__qpzone_resigndelete(qpdb, rbtversion, - header DNS__DB_FLARG_PASS); - } else { - /* - * The rdataset doesn't exist, so we don't need to do anything - * to satisfy the deletion request. - */ - dns_slabheader_destroy(&newheader); - if ((options & DNS_DBSUB_EXACT) != 0) { - result = DNS_R_NOTEXACT; - } else { - result = DNS_R_UNCHANGED; - } - } - - if (result == ISC_R_SUCCESS && newrdataset != NULL) { - dns__qpdb_bindrdataset(qpdb, qpnode, newheader, 0, - isc_rwlocktype_write, - newrdataset DNS__DB_FLARG_PASS); - } - - if (result == DNS_R_NXRRSET && newrdataset != NULL && - (options & DNS_DBSUB_WANTOLD) != 0) - { - dns__qpdb_bindrdataset(qpdb, qpnode, header, 0, - isc_rwlocktype_write, - newrdataset DNS__DB_FLARG_PASS); - } - -unlock: - NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - - /* - * Update the zone's secure status. If version is non-NULL - * this is deferred until dns__qpdb_closeversion() is called. - */ - if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(qpdb)) { - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - version = qpdb->current_version; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - dns__qpdb_setsecure(db, version, qpdb->origin_node); - } - return (result); } @@ -3483,15 +2043,12 @@ dns__qpdb_deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_rdatatype_t covers DNS__DB_FLARG) { dns_qpdb_t *qpdb = (dns_qpdb_t *)db; dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - dns_qpdb_version_t *rbtversion = version; - dns_fixedname_t fname; - dns_name_t *nodename = dns_fixedname_initname(&fname); isc_result_t result; dns_slabheader_t *newheader = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_QPDB(qpdb)); - INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb); + REQUIRE(version == NULL); if (type == dns_rdatatype_any) { return (ISC_R_NOTIMPLEMENTED); @@ -3504,29 +2061,12 @@ dns__qpdb_deleterdataset(dns_db_t *db, dns_dbnode_t *node, newheader->type = DNS_TYPEPAIR_VALUE(type, covers); dns__qpdb_setttl(newheader, 0); atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); - if (rbtversion != NULL) { - newheader->serial = rbtversion->serial; - } - - dns__qpdb_nodefullname(db, node, nodename); NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - result = dns__qpdb_add(qpdb, qpnode, nodename, rbtversion, newheader, - DNS_DBADD_FORCE, false, NULL, - 0 DNS__DB_FLARG_PASS); + result = dns__qpdb_add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, + false, NULL, 0 DNS__DB_FLARG_PASS); NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); - /* - * Update the zone's secure status. If version is non-NULL - * this is deferred until dns__qpdb_closeversion() is called. - */ - if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(qpdb)) { - RWLOCK(&qpdb->lock, isc_rwlocktype_read); - version = qpdb->current_version; - RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); - dns__qpdb_setsecure(db, version, qpdb->origin_node); - } - return (result); } @@ -3589,7 +2129,6 @@ dns__qpdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { isc_rwlocktype_none DNS__DB_FLARG_PASS); *nodep = qpdb->origin_node; } else { - INSIST(IS_CACHE(qpdb)); result = ISC_R_NOTFOUND; } @@ -3612,31 +2151,17 @@ dns__qpdb_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) { RWUNLOCK(&qpdb->node_locks[qpnode->locknum].lock, type); } -isc_result_t -dns__qpdb_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { - dns_qpdb_t *qpdb = (dns_qpdb_t *)db; - dns_qpdata_t *qpnode = (dns_qpdata_t *)node; - isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - - REQUIRE(VALID_QPDB(qpdb)); - REQUIRE(node != NULL); - REQUIRE(name != NULL); - - TREE_RDLOCK(&qpdb->tree_lock, &tlocktype); - dns_name_copy(qpnode->name, name); - TREE_UNLOCK(&qpdb->tree_lock, &tlocktype); - - return (ISC_R_SUCCESS); -} - isc_result_t dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc, char *argv[], void *driverarg ISC_ATTR_UNUSED, dns_db_t **dbp) { dns_qpdb_t *qpdb = NULL; isc_result_t result; - int i; isc_mem_t *hmctx = mctx; + int i; + + /* This database implementation only supports cache semantics */ + REQUIRE(type == dns_dbtype_cache); qpdb = isc_mem_get(mctx, sizeof(*qpdb)); *qpdb = (dns_qpdb_t){ @@ -3645,7 +2170,6 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, .current_serial = 1, .least_serial = 1, .next_serial = 2, - .open_versions = ISC_LIST_INITIALIZER, }; isc_refcount_init(&qpdb->common.references, 1); @@ -3657,15 +2181,8 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, hmctx = (isc_mem_t *)argv[0]; } - if (type == dns_dbtype_cache) { - qpdb->common.methods = &dns__qpdb_cachemethods; - qpdb->common.attributes |= DNS_DBATTR_CACHE; - } else if (type == dns_dbtype_stub) { - qpdb->common.methods = &dns__qpdb_zonemethods; - qpdb->common.attributes |= DNS_DBATTR_STUB; - } else { - qpdb->common.methods = &dns__qpdb_zonemethods; - } + qpdb->common.methods = &dns__qpdb_cachemethods; + qpdb->common.attributes |= DNS_DBATTR_CACHE; isc_rwlock_init(&qpdb->lock); TREE_INITLOCK(&qpdb->tree_lock); @@ -3677,14 +2194,7 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, * as commented with the definition of DEFAULT_CACHE_NODE_LOCK_COUNT. */ if (qpdb->node_lock_count == 0) { - if (IS_CACHE(qpdb)) { - qpdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT; - } else { - qpdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT; - } - } else if (qpdb->node_lock_count < 2 && IS_CACHE(qpdb)) { - result = ISC_R_RANGE; - goto cleanup_tree_lock; + qpdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT; } INSIST(qpdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH)); qpdb->node_locks = isc_mem_cget(mctx, qpdb->node_lock_count, @@ -3692,13 +2202,11 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, qpdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL); - if (IS_CACHE(qpdb)) { - dns_rdatasetstats_create(mctx, &qpdb->rrsetstats); - qpdb->lru = isc_mem_cget(mctx, qpdb->node_lock_count, - sizeof(dns_slabheaderlist_t)); - for (i = 0; i < (int)qpdb->node_lock_count; i++) { - ISC_LIST_INIT(qpdb->lru[i]); - } + dns_rdatasetstats_create(mctx, &qpdb->rrsetstats); + qpdb->lru = isc_mem_cget(mctx, qpdb->node_lock_count, + sizeof(dns_slabheaderlist_t)); + for (i = 0; i < (int)qpdb->node_lock_count; i++) { + ISC_LIST_INIT(qpdb->lru[i]); } /* @@ -3710,9 +2218,8 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, qpdb->heaps[i] = NULL; } - qpdb->sooner = IS_CACHE(qpdb) ? ttl_sooner : resign_sooner; for (i = 0; i < (int)qpdb->node_lock_count; i++) { - isc_heap_create(hmctx, qpdb->sooner, set_index, 0, + isc_heap_create(hmctx, ttl_sooner, set_index, 0, &qpdb->heaps[i]); } @@ -3757,65 +2264,12 @@ dns__qpdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, dns_qp_create(mctx, &qpmethods, qpdb, &qpdb->nsec); dns_qp_create(mctx, &qpmethods, qpdb, &qpdb->nsec3); - /* - * In order to set the node callback bit correctly in zone databases, - * we need to know if the node has the origin name of the zone. - * In loading_addrdataset() we could simply compare the new name - * to the origin name, but this is expensive. Also, we don't know the - * node name in dns__qpdb_addrdataset(), so we need another way of - * knowing the zone's top. - * - * We now explicitly create a node for the zone's origin, and then - * we simply remember the node's address. This is safe, because - * the top-of-zone node can never be deleted, nor can its address - * change. - */ - if (!IS_CACHE(qpdb)) { - qpdb->origin_node = dns_qpdata_create(qpdb, - &qpdb->common.origin); - result = dns_qp_insert(qpdb->tree, qpdb->origin_node, 0); - INSIST(result == ISC_R_SUCCESS); - INSIST(qpdb->origin_node != NULL); - qpdb->origin_node->nsec = DNS_DB_NSEC_NORMAL; - - /* - * Add an apex node to the NSEC3 tree so that NSEC3 searches - * return partial matches when there is only a single NSEC3 - * record in the tree. - */ - qpdb->nsec3_origin_node = - dns_qpdata_create(qpdb, &qpdb->common.origin); - result = dns_qp_insert(qpdb->nsec3, qpdb->nsec3_origin_node, 0); - INSIST(result == ISC_R_SUCCESS); - INSIST(qpdb->nsec3_origin_node != NULL); - qpdb->nsec3_origin_node->nsec = DNS_DB_NSEC_NSEC3; - } - - /* - * Version Initialization. - */ - qpdb->current_version = allocate_version(mctx, 1, 1, false); - qpdb->current_version->qpdb = qpdb; - isc_rwlock_init(&qpdb->current_version->rwlock); - - /* - * Keep the current version in the open list so that list operation - * won't happen in normal lookup operations. - */ - PREPEND(qpdb->open_versions, qpdb->current_version, link); - qpdb->common.magic = DNS_DB_MAGIC; qpdb->common.impmagic = QPDB_MAGIC; *dbp = (dns_db_t *)qpdb; return (ISC_R_SUCCESS); - -cleanup_tree_lock: - TREE_DESTROYLOCK(&qpdb->tree_lock); - isc_rwlock_destroy(&qpdb->lock); - isc_mem_put(mctx, qpdb, sizeof(*qpdb)); - return (result); } /* @@ -3828,11 +2282,6 @@ rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { rbtiterator = (qpdb_rdatasetiter_t *)(*iteratorp); - if (rbtiterator->common.version != NULL) { - dns__qpdb_closeversion(rbtiterator->common.db, - &rbtiterator->common.version, - false DNS__DB_FLARG_PASS); - } dns__db_detachnode(rbtiterator->common.db, &rbtiterator->common.node DNS__DB_FLARG_PASS); isc_mem_put(rbtiterator->common.db->mctx, rbtiterator, @@ -3854,9 +2303,9 @@ iterator_active(dns_qpdb_t *qpdb, qpdb_rdatasetiter_t *rbtiterator, } /* - * If this is a zone or this header still active then return it. + * If this header is still active then return it. */ - if (!IS_CACHE(qpdb) || ACTIVE(header, rbtiterator->common.now)) { + if (ACTIVE(header, rbtiterator->common.now)) { return (true); } @@ -3875,9 +2324,7 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpdb_rdatasetiter_t *rbtiterator = (qpdb_rdatasetiter_t *)iterator; dns_qpdb_t *qpdb = (dns_qpdb_t *)(rbtiterator->common.db); dns_qpdata_t *qpnode = rbtiterator->common.node; - dns_qpdb_version_t *rbtversion = rbtiterator->common.version; dns_slabheader_t *header = NULL, *top_next = NULL; - uint32_t serial = IS_CACHE(qpdb) ? 1 : rbtversion->serial; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); @@ -3890,8 +2337,7 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { break; } header = header->down; - } else if (header->serial <= serial && !IGNORE(header)) - { + } else if (header->serial <= 1 && !IGNORE(header)) { if (!iterator_active(qpdb, rbtiterator, header)) { header = NULL; @@ -3922,9 +2368,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpdb_rdatasetiter_t *rbtiterator = (qpdb_rdatasetiter_t *)iterator; dns_qpdb_t *qpdb = (dns_qpdb_t *)(rbtiterator->common.db); dns_qpdata_t *qpnode = rbtiterator->common.node; - dns_qpdb_version_t *rbtversion = rbtiterator->common.version; dns_slabheader_t *header = NULL, *top_next = NULL; - uint32_t serial = IS_CACHE(qpdb) ? 1 : rbtversion->serial; dns_typepair_t type, negtype; dns_rdatatype_t rdtype, covers; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; @@ -3973,8 +2417,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { break; } header = header->down; - } else if (header->serial <= serial && !IGNORE(header)) - { + } else if (header->serial <= 1 && !IGNORE(header)) { if (!iterator_active(qpdb, rbtiterator, header)) { header = NULL; @@ -4552,64 +2995,6 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) { return (ISC_R_SUCCESS); } -void -dns__qpdb_freeglue(dns_glue_t *glue_list) { - if (glue_list == (void *)-1) { - return; - } - - dns_glue_t *glue = glue_list; - while (glue != NULL) { - dns_glue_t *next = glue->next; - - if (dns_rdataset_isassociated(&glue->rdataset_a)) { - dns_rdataset_disassociate(&glue->rdataset_a); - } - if (dns_rdataset_isassociated(&glue->sigrdataset_a)) { - dns_rdataset_disassociate(&glue->sigrdataset_a); - } - - if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { - dns_rdataset_disassociate(&glue->rdataset_aaaa); - } - if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) { - dns_rdataset_disassociate(&glue->sigrdataset_aaaa); - } - - dns_rdataset_invalidate(&glue->rdataset_a); - dns_rdataset_invalidate(&glue->sigrdataset_a); - dns_rdataset_invalidate(&glue->rdataset_aaaa); - dns_rdataset_invalidate(&glue->sigrdataset_aaaa); - - isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue)); - - glue = next; - } -} - -static void -free_gluelist_rcu(struct rcu_head *rcu_head) { - dns_glue_t *glue = caa_container_of(rcu_head, dns_glue_t, rcu_head); - - dns__qpdb_freeglue(glue); -} - -static void -free_gluetable(struct cds_wfs_stack *glue_stack) { - struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack); - struct cds_wfs_node *node = NULL, *next = NULL; - - rcu_read_lock(); - cds_wfs_for_each_blocking_safe(head, node, next) { - dns_slabheader_t *header = - caa_container_of(node, dns_slabheader_t, wfs_node); - dns_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL); - - call_rcu(&glue->rcu_head, free_gluelist_rcu); - } - rcu_read_unlock(); -} - void dns__qpdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED, dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { @@ -4620,27 +3005,19 @@ dns__qpdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED, isc_heap_delete(header->heap, header->heap_index); } - if (IS_CACHE(qpdb)) { - update_rrsetstats(qpdb->rrsetstats, header->type, - atomic_load_acquire(&header->attributes), - false); + update_rrsetstats(qpdb->rrsetstats, header->type, + atomic_load_acquire(&header->attributes), false); - if (ISC_LINK_LINKED(header, link)) { - int idx = QPDB_HEADERNODE(header)->locknum; - INSIST(IS_CACHE(qpdb)); - ISC_LIST_UNLINK(qpdb->lru[idx], header, link); - } + if (ISC_LINK_LINKED(header, link)) { + int idx = QPDB_HEADERNODE(header)->locknum; + ISC_LIST_UNLINK(qpdb->lru[idx], header, link); + } - if (header->noqname != NULL) { - dns_slabheader_freeproof(db->mctx, &header->noqname); - } - if (header->closest != NULL) { - dns_slabheader_freeproof(db->mctx, &header->closest); - } - } else { - if (header->glue_list) { - dns__qpdb_freeglue(header->glue_list); - } + if (header->noqname != NULL) { + dns_slabheader_freeproof(db->mctx, &header->noqname); + } + if (header->closest != NULL) { + dns_slabheader_freeproof(db->mctx, &header->closest); } } diff --git a/lib/dns/qpdb_p.h b/lib/dns/qpdb_p.h index 23c38243e1..e619048423 100644 --- a/lib/dns/qpdb_p.h +++ b/lib/dns/qpdb_p.h @@ -74,14 +74,8 @@ struct dns_qpdata { * after acquiring the tree lock. */ unsigned int : 0; /* start of bitfields c/o tree lock */ - unsigned int is_root : 1; /*%< range is 0..1 */ - unsigned int color : 1; /*%< range is 0..1 */ unsigned int find_callback : 1; /*%< range is 0..1 */ - bool absolute : 1; /*%< node with absolute DNS name */ unsigned int nsec : 2; /*%< range is 0..3 */ - unsigned int namelen : 8; /*%< range is 1..255 */ - unsigned int offsetlen : 8; /*%< range is 1..128 */ - unsigned int oldnamelen : 8; /*%< range is 1..255 */ unsigned int : 0; /* end of bitfields c/o tree lock */ /*@}*/ @@ -103,7 +97,7 @@ struct dns_qpdata { /*@{*/ /*! - * These values are used in the RBT DB implementation. The appropriate + * These values are used in the QPDB implementation. The appropriate * node lock must be held before accessing them. * * Note: The two "unsigned int :0;" unnamed bitfields on either @@ -122,7 +116,6 @@ struct dns_qpdata { void *data; uint8_t : 0; /* start of bitfields c/o node lock */ uint8_t dirty : 1; - uint8_t wild : 1; uint8_t : 0; /* end of bitfields c/o node lock */ uint16_t locknum; /* note that this is not in the bitfield */ isc_refcount_t references; @@ -138,43 +131,6 @@ typedef struct qpdb_changed { typedef ISC_LIST(qpdb_changed_t) qpdb_changedlist_t; -struct dns_qpdb_version { - /* Not locked */ - uint32_t serial; - dns_qpdb_t *qpdb; - /* - * Protected in the refcount routines. - * XXXJT: should we change the lock policy based on the refcount - * performance? - */ - isc_refcount_t references; - /* Locked by database lock. */ - bool writer; - bool commit_ok; - qpdb_changedlist_t changed_list; - dns_slabheaderlist_t resigned_list; - ISC_LINK(dns_qpdb_version_t) link; - bool secure; - bool havensec3; - /* NSEC3 parameters */ - dns_hash_t hash; - uint8_t flags; - uint16_t iterations; - uint8_t salt_length; - unsigned char salt[DNS_NSEC3_SALTSIZE]; - - /* - * records and xfrsize are covered by rwlock. - */ - isc_rwlock_t rwlock; - uint64_t records; - uint64_t xfrsize; - - struct cds_wfs_stack glue_stack; -}; - -typedef ISC_LIST(dns_qpdb_version_t) qpdb_versionlist_t; - struct dns_qpdb { /* Unlocked. */ dns_db_t common; @@ -196,9 +152,6 @@ struct dns_qpdb { uint32_t current_serial; uint32_t least_serial; uint32_t next_serial; - dns_qpdb_version_t *current_version; - dns_qpdb_version_t *future_version; - qpdb_versionlist_t open_versions; isc_loop_t *loop; dns_dbnode_t *soanode; dns_dbnode_t *nsnode; @@ -242,7 +195,6 @@ struct dns_qpdb { */ isc_mem_t *hmctx; isc_heap_t **heaps; - isc_heapcompare_t sooner; /* Locked by tree_lock. */ dns_qp_t *tree; @@ -258,7 +210,6 @@ struct dns_qpdb { */ typedef struct { dns_qpdb_t *qpdb; - dns_qpdb_version_t *rbtversion; uint32_t serial; unsigned int options; dns_qpchain_t chain; @@ -448,9 +399,6 @@ dns__qpdb_bindrdataset(dns_qpdb_t *qpdb, dns_qpdata_t *node, isc_result_t dns__qpdb_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name); -void -dns__qpdb_freeglue(dns_glue_t *glue_list); - void dns__qpdb_newref(dns_qpdb_t *qpdb, dns_qpdata_t *node, isc_rwlocktype_t locktype DNS__DB_FLARG); @@ -477,23 +425,14 @@ dns__qpdb_decref(dns_qpdb_t *qpdb, dns_qpdata_t *node, uint32_t least_serial, isc_result_t dns__qpdb_add(dns_qpdb_t *qpdb, dns_qpdata_t *qpnode, - const dns_name_t *nodename, dns_qpdb_version_t *rbtversion, - dns_slabheader_t *newheader, unsigned int options, bool loading, - dns_rdataset_t *addedrdataset, isc_stdtime_t now DNS__DB_FLARG); + const dns_name_t *nodename, dns_slabheader_t *newheader, + unsigned int options, bool loading, dns_rdataset_t *addedrdataset, + isc_stdtime_t now DNS__DB_FLARG); /*%< * Add a slab header 'newheader' to a node in an RBT database. * The caller must have the node write-locked. */ -void -dns__qpdb_setsecure(dns_db_t *db, dns_qpdb_version_t *version, - dns_dbnode_t *origin); -/*%< - * Update the secure status for an RBT database version 'version'. - * The version will be marked secure if it is fully signed and - * and contains a complete NSEC/NSEC3 chain. - */ - void dns__qpdb_mark(dns_slabheader_t *header, uint_least16_t flag); /*%< @@ -509,43 +448,6 @@ dns__qpdb_setttl(dns_slabheader_t *header, dns_ttl_t newttl); * also update the TTL heap accordingly. */ -/* - * Functions specific to zone databases that are also called from qpdb.c. - */ -void -dns__qpzone_resigninsert(dns_qpdb_t *qpdb, int idx, - dns_slabheader_t *newheader); -void -dns__qpzone_resigndelete(dns_qpdb_t *qpdb, dns_qpdb_version_t *version, - dns_slabheader_t *header DNS__DB_FLARG); -/*%< - * Insert/delete a node from the zone database's resigning heap. - */ - -isc_result_t -dns__qpzone_wildcardmagic(dns_qpdb_t *qpdb, const dns_name_t *name, bool lock); -/*%< - * Add the necessary magic for the wildcard name 'name' - * to be found in 'qpdb'. - * - * In order for wildcard matching to work correctly in - * zone_find(), we must ensure that a node for the wildcarding - * level exists in the database, and has its 'find_callback' - * and 'wild' bits set. - * - * E.g. if the wildcard name is "*.sub.example." then we - * must ensure that "sub.example." exists and is marked as - * a wildcard level. - * - * The tree must be write-locked. - */ -isc_result_t -dns__qpzone_addwildcards(dns_qpdb_t *qpdb, const dns_name_t *name, bool lock); -/*%< - * If 'name' is or contains a wildcard name, create a node for it in the - * database. The tree must be write-locked. - */ - /* * Cache-specific functions that are called from qpdb.c */ diff --git a/tests/dns/qpdb_test.c b/tests/dns/qpdb_test.c index 9002f95a1c..e7a6a296b0 100644 --- a/tests/dns/qpdb_test.c +++ b/tests/dns/qpdb_test.c @@ -42,179 +42,6 @@ #undef CHECK #include -const char *ownercase_vectors[12][2] = { - { - "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz", - "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz", - }, - { - "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz", - "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ", - }, - { - "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ", - "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz", - }, - { - "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ", - "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz", - }, - { - "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVxXyYzZ", - "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvxxyyzz", - }, - { - "WwW.ExAmPlE.OrG", - "wWw.eXaMpLe.oRg", - }, - { - "_SIP.tcp.example.org", - "_sip.TCP.example.org", - }, - { - "bind-USERS.lists.example.org", - "bind-users.lists.example.org", - }, - { - "a0123456789.example.org", - "A0123456789.example.org", - }, - { - "\\000.example.org", - "\\000.example.org", - }, - { - "wWw.\\000.isc.org", - "www.\\000.isc.org", - }, - { - "\255.example.org", - "\255.example.ORG", - } -}; - -static bool -ownercase_test_one(const char *str1, const char *str2) { - isc_result_t result; - db_nodelock_t node_locks[1]; - dns_qpdb_t qpdb = { - .common.methods = &dns__qpdb_zonemethods, - .common.mctx = mctx, - .node_locks = node_locks, - }; - dns_qpdata_t rbtnode = { .locknum = 0 }; - dns_slabheader_t header = { - .node = &rbtnode, - .db = (dns_db_t *)&qpdb, - }; - unsigned char *raw = (unsigned char *)(&header) + sizeof(header); - dns_rdataset_t rdataset = { - .magic = DNS_RDATASET_MAGIC, - .slab = { .db = (dns_db_t *)&qpdb, - .node = &rbtnode, - .raw = raw }, - .methods = &dns_rdataslab_rdatasetmethods, - }; - isc_buffer_t b; - dns_fixedname_t fname1, fname2; - dns_name_t *name1 = dns_fixedname_initname(&fname1); - dns_name_t *name2 = dns_fixedname_initname(&fname2); - - memset(node_locks, 0, sizeof(node_locks)); - /* Minimal initialization of the mock objects */ - NODE_INITLOCK(&qpdb.node_locks[0].lock); - - isc_buffer_constinit(&b, str1, strlen(str1)); - isc_buffer_add(&b, strlen(str1)); - result = dns_name_fromtext(name1, &b, dns_rootname, 0, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - - isc_buffer_constinit(&b, str2, strlen(str2)); - isc_buffer_add(&b, strlen(str2)); - result = dns_name_fromtext(name2, &b, dns_rootname, 0, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - - /* Store the case from name1 */ - dns_rdataset_setownercase(&rdataset, name1); - - assert_true(CASESET(&header)); - - /* Retrieve the case to name2 */ - dns_rdataset_getownercase(&rdataset, name2); - - NODE_DESTROYLOCK(&qpdb.node_locks[0].lock); - - return (dns_name_caseequal(name1, name2)); -} - -ISC_RUN_TEST_IMPL(ownercase) { - UNUSED(state); - - for (size_t n = 0; n < ARRAY_SIZE(ownercase_vectors); n++) { - assert_true(ownercase_test_one(ownercase_vectors[n][0], - ownercase_vectors[n][1])); - } - - assert_false(ownercase_test_one("W.example.org", "\\000.example.org")); - - /* Ö and ö in ISO Latin 1 */ - assert_false(ownercase_test_one("\\216", "\\246")); -} - -ISC_RUN_TEST_IMPL(setownercase) { - isc_result_t result; - db_nodelock_t node_locks[1]; - dns_qpdb_t qpdb = { - .common.methods = &dns__qpdb_zonemethods, - .common.mctx = mctx, - .node_locks = node_locks, - }; - dns_qpdata_t rbtnode = { .locknum = 0 }; - dns_slabheader_t header = { - .node = &rbtnode, - .db = (dns_db_t *)&qpdb, - }; - unsigned char *raw = (unsigned char *)(&header) + sizeof(header); - dns_rdataset_t rdataset = { - .magic = DNS_RDATASET_MAGIC, - .slab = { .db = (dns_db_t *)&qpdb, - .node = &rbtnode, - .raw = raw }, - .methods = &dns_rdataslab_rdatasetmethods, - }; - const char *str1 = - "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; - isc_buffer_t b; - dns_fixedname_t fname1, fname2; - dns_name_t *name1 = dns_fixedname_initname(&fname1); - dns_name_t *name2 = dns_fixedname_initname(&fname2); - - UNUSED(state); - - /* Minimal initialization of the mock objects */ - memset(node_locks, 0, sizeof(node_locks)); - NODE_INITLOCK(&qpdb.node_locks[0].lock); - - isc_buffer_constinit(&b, str1, strlen(str1)); - isc_buffer_add(&b, strlen(str1)); - result = dns_name_fromtext(name1, &b, dns_rootname, 0, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - - isc_buffer_constinit(&b, str1, strlen(str1)); - isc_buffer_add(&b, strlen(str1)); - result = dns_name_fromtext(name2, &b, dns_rootname, 0, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - - assert_false(CASESET(&header)); - - /* Retrieve the case to name2 */ - dns_rdataset_getownercase(&rdataset, name2); - - NODE_DESTROYLOCK(&qpdb.node_locks[0].lock); - - assert_true(dns_name_caseequal(name1, name2)); -} - /* * Add to a cache DB 'db' an rdataset of type 'rtype' at a name * .example.com. The rdataset would contain one data, and rdata_len is @@ -372,8 +199,6 @@ ISC_RUN_TEST_IMPL(overmempurge_longname) { } ISC_TEST_LIST_START -ISC_TEST_ENTRY(ownercase) -ISC_TEST_ENTRY(setownercase) ISC_TEST_ENTRY(overmempurge_bigrdata) ISC_TEST_ENTRY(overmempurge_longname) ISC_TEST_LIST_END