/* 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. */
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")])],
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])
rbtdb.c \
rbtdb_p.h \
qp-cachedb.c \
- qp-zonedb.c \
qpdb_p.h \
qpdb.c \
rcode.c \
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,
.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,
.unlocknode = dns__qpdb_unlocknode,
.expiredata = expiredata,
.deletedata = dns__qpdb_deletedata,
- .nodefullname = dns__qpdb_nodefullname,
};
/*
+++ /dev/null
-/*
- * 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 <inttypes.h>
-#include <stdbool.h>
-#include <sys/mman.h>
-
-#include <isc/ascii.h>
-#include <isc/async.h>
-#include <isc/atomic.h>
-#include <isc/crc64.h>
-#include <isc/file.h>
-#include <isc/hash.h>
-#include <isc/hashmap.h>
-#include <isc/heap.h>
-#include <isc/hex.h>
-#include <isc/loop.h>
-#include <isc/mem.h>
-#include <isc/mutex.h>
-#include <isc/once.h>
-#include <isc/random.h>
-#include <isc/refcount.h>
-#include <isc/result.h>
-#include <isc/rwlock.h>
-#include <isc/serial.h>
-#include <isc/stdio.h>
-#include <isc/string.h>
-#include <isc/time.h>
-#include <isc/urcu.h>
-#include <isc/util.h>
-
-#include <dns/callbacks.h>
-#include <dns/db.h>
-#include <dns/dbiterator.h>
-#include <dns/fixedname.h>
-#include <dns/log.h>
-#include <dns/masterdump.h>
-#include <dns/nsec.h>
-#include <dns/nsec3.h>
-#include <dns/qp.h>
-#include <dns/rbt.h>
-#include <dns/rdata.h>
-#include <dns/rdataset.h>
-#include <dns/rdatasetiter.h>
-#include <dns/rdataslab.h>
-#include <dns/rdatastruct.h>
-#include <dns/stats.h>
-#include <dns/time.h>
-#include <dns/view.h>
-#include <dns/zone.h>
-#include <dns/zonekey.h>
-
-#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);
-}
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/view.h>
-#include <dns/zone.h>
#include <dns/zonekey.h>
#include "db_p.h"
#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)
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
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
* 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
*/
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.
*/
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.
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.
}
}
-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);
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.
*/
REQUIRE(*nlocktypep != isc_rwlocktype_none);
UNUSED(pruning);
+ UNUSED(least_serial);
nodelock = &qpdb->node_locks[bucket];
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);
}
/*
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);
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;
}
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;
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;
}
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
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));
- iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
+ UNUSED(version);
- 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);
+ iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
- (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;
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);
* 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) {
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
* 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)),
* 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 ||
}
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
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;
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 {
}
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) {
* we INSIST on it.
*/
INSIST(!loading);
- INSIST(rbtversion == NULL ||
- rbtversion->serial >= topheader->serial);
if (topheader_prev != NULL) {
topheader_prev->next = newheader;
} else {
}
}
- 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,
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) {
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;
dns_name_t *name = NULL;
REQUIRE(VALID_QPDB(qpdb));
- INSIST(rbtversion == NULL || rbtversion->qpdb == qpdb);
-
- 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);
- }
+ REQUIRE(version == NULL);
- 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,
}
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;
}
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;
- }
- } 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);
- }
+ 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;
}
/*
* 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) {
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;
}
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) {
}
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);
}
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);
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);
}
isc_rwlocktype_none DNS__DB_FLARG_PASS);
*nodep = qpdb->origin_node;
} else {
- INSIST(IS_CACHE(qpdb));
result = ISC_R_NOTFOUND;
}
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){
.current_serial = 1,
.least_serial = 1,
.next_serial = 2,
- .open_versions = ISC_LIST_INITIALIZER,
};
isc_refcount_init(&qpdb->common.references, 1);
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);
* 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,
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]);
}
/*
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]);
}
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);
}
/*
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,
}
/*
- * 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);
}
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);
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;
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;
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;
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) {
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);
}
}
* 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 */
/*@}*/
/*@{*/
/*!
- * 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
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;
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;
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;
*/
isc_mem_t *hmctx;
isc_heap_t **heaps;
- isc_heapcompare_t sooner;
/* Locked by tree_lock. */
dns_qp_t *tree;
*/
typedef struct {
dns_qpdb_t *qpdb;
- dns_qpdb_version_t *rbtversion;
uint32_t serial;
unsigned int options;
dns_qpchain_t chain;
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);
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);
/*%<
* 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
*/
#undef CHECK
#include <tests/dns.h>
-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
* <idx>.example.com. The rdataset would contain one data, and rdata_len is
}
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