2023-10-03 18:55:24 -07:00
|
|
|
/*
|
|
|
|
* 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>
|
2025-02-04 16:50:27 +01:00
|
|
|
#include <stdalign.h>
|
2023-10-03 18:55:24 -07:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
#include <isc/ascii.h>
|
|
|
|
#include <isc/async.h>
|
|
|
|
#include <isc/atomic.h>
|
|
|
|
#include <isc/file.h>
|
|
|
|
#include <isc/heap.h>
|
|
|
|
#include <isc/hex.h>
|
2024-08-14 13:25:50 +02:00
|
|
|
#include <isc/log.h>
|
2023-10-03 18:55:24 -07:00
|
|
|
#include <isc/loop.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/mutex.h>
|
2025-02-04 18:02:29 +01:00
|
|
|
#include <isc/os.h>
|
2023-10-03 18:55:24 -07:00
|
|
|
#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>
|
2025-03-13 13:01:47 -07:00
|
|
|
#include <dns/dnssec.h>
|
2023-10-03 18:55:24 -07:00
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/masterdump.h>
|
2024-03-11 18:47:01 -07:00
|
|
|
#include <dns/name.h>
|
2023-10-03 18:55:24 -07:00
|
|
|
#include <dns/nsec.h>
|
|
|
|
#include <dns/nsec3.h>
|
|
|
|
#include <dns/qp.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 "db_p.h"
|
|
|
|
#include "qpzone_p.h"
|
2025-08-12 12:21:56 +02:00
|
|
|
#include "rdataslab_p.h"
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
#define CHECK(op) \
|
|
|
|
do { \
|
|
|
|
result = (op); \
|
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto failure; \
|
|
|
|
} while (0)
|
|
|
|
|
2024-04-29 15:29:33 -07:00
|
|
|
#define HEADERNODE(h) ((qpznode_t *)((h)->node))
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
#define QPDB_ATTR_LOADED 0x01
|
|
|
|
#define QPDB_ATTR_LOADING 0x02
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
#define QPDBITER_ORIGIN_NODE(qpdb, iterator) \
|
|
|
|
((iterator)->node == (qpdb)->origin)
|
|
|
|
#define QPDBITER_NSEC_ORIGIN_NODE(qpdb, iterator) \
|
|
|
|
((iterator)->node == (qpdb)->nsec_origin)
|
|
|
|
#define QPDBITER_NSEC3_ORIGIN_NODE(qpdb, iterator) \
|
|
|
|
((iterator)->node == (qpdb)->nsec3_origin)
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
/*%
|
|
|
|
* Note that "impmagic" is not the first four bytes of the struct, so
|
|
|
|
* ISC_MAGIC_VALID cannot be used.
|
|
|
|
*/
|
|
|
|
#define QPZONE_DB_MAGIC ISC_MAGIC('Q', 'Z', 'D', 'B')
|
|
|
|
#define VALID_QPZONE(qpdb) \
|
|
|
|
((qpdb) != NULL && (qpdb)->common.impmagic == QPZONE_DB_MAGIC)
|
|
|
|
|
|
|
|
typedef struct qpzonedb qpzonedb_t;
|
2024-04-29 15:29:33 -07:00
|
|
|
typedef struct qpznode qpznode_t;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-07-08 15:52:35 +02:00
|
|
|
typedef struct qpzone_bucket {
|
|
|
|
/* Per-bucket lock. */
|
|
|
|
isc_rwlock_t lock;
|
|
|
|
|
|
|
|
/* Padding to prevent false sharing between locks. */
|
|
|
|
uint8_t __padding[ISC_OS_CACHELINE_SIZE -
|
|
|
|
(sizeof(isc_rwlock_t)) % ISC_OS_CACHELINE_SIZE];
|
|
|
|
} qpzone_bucket_t;
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
static qpzone_bucket_t qpzone_buckets_g[1024];
|
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
typedef struct qpz_changed {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node;
|
2023-10-03 18:55:24 -07:00
|
|
|
bool dirty;
|
2024-04-29 15:45:26 -07:00
|
|
|
ISC_LINK(struct qpz_changed) link;
|
|
|
|
} qpz_changed_t;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
typedef ISC_LIST(qpz_changed_t) qpz_changedlist_t;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-08-13 09:30:45 +02:00
|
|
|
typedef struct qpz_resigned {
|
|
|
|
dns_slabheader_t *header;
|
|
|
|
ISC_LINK(struct qpz_resigned) link;
|
|
|
|
} qpz_resigned_t;
|
|
|
|
|
|
|
|
typedef ISC_LIST(qpz_resigned_t) qpz_resignedlist_t;
|
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
typedef struct qpz_version qpz_version_t;
|
|
|
|
struct qpz_version {
|
2023-10-03 18:55:24 -07:00
|
|
|
/* Not locked */
|
|
|
|
uint32_t serial;
|
|
|
|
qpzonedb_t *qpdb;
|
|
|
|
isc_refcount_t references;
|
|
|
|
/* Locked by database lock. */
|
|
|
|
bool writer;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_changedlist_t changed_list;
|
2025-08-13 09:30:45 +02:00
|
|
|
qpz_resignedlist_t resigned_list;
|
2024-04-29 15:45:26 -07:00
|
|
|
ISC_LINK(qpz_version_t) link;
|
2023-10-03 18:55:24 -07:00
|
|
|
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;
|
|
|
|
|
2024-12-03 15:07:30 +01:00
|
|
|
struct cds_wfs_stack glue_stack;
|
2023-10-03 18:55:24 -07:00
|
|
|
};
|
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
typedef ISC_LIST(qpz_version_t) qpz_versionlist_t;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
/* Resigning heap indirection to allow ref counting */
|
|
|
|
typedef struct qpz_heap {
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
isc_refcount_t references;
|
|
|
|
/* Locks the data in this struct */
|
|
|
|
isc_mutex_t lock;
|
|
|
|
isc_heap_t *heap;
|
|
|
|
} qpz_heap_t;
|
|
|
|
|
|
|
|
ISC_REFCOUNT_STATIC_DECL(qpz_heap);
|
|
|
|
|
2024-04-29 15:29:33 -07:00
|
|
|
struct qpznode {
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
DBNODE_FIELDS;
|
2025-01-30 14:42:57 -08:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
qpz_heap_t *heap;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpzonedb_t *qpdb;
|
2025-01-30 14:42:57 -08:00
|
|
|
/*
|
|
|
|
* 'erefs' counts external references held by a caller: for
|
|
|
|
* example, it could be incremented by dns_db_findnode(),
|
|
|
|
* and decremented by dns_db_detachnode().
|
|
|
|
*
|
|
|
|
* 'references' counts internal references to the node object,
|
|
|
|
* including the one held by the QP trie so the node won't be
|
|
|
|
* deleted while it's quiescently stored in the database - even
|
|
|
|
* though 'erefs' may be zero because no external caller is
|
|
|
|
* using it at the time.
|
|
|
|
*
|
|
|
|
* Generally when 'erefs' is incremented or decremented,
|
|
|
|
* 'references' is too. When both go to zero (meaning callers
|
|
|
|
* and the database have both released the object) the object
|
|
|
|
* is freed.
|
|
|
|
*
|
|
|
|
* Whenever 'erefs' is incremented from zero, we also aquire a
|
|
|
|
* node use reference (see 'qpzonedb->references' below), and
|
|
|
|
* release it when 'erefs' goes back to zero. This prevents the
|
|
|
|
* database from being shut down until every caller has released
|
|
|
|
* all nodes.
|
|
|
|
*/
|
2023-10-03 18:55:24 -07:00
|
|
|
isc_refcount_t references;
|
2023-12-02 01:04:28 -08:00
|
|
|
isc_refcount_t erefs;
|
2025-01-30 14:42:57 -08:00
|
|
|
|
2025-05-26 17:36:33 +02:00
|
|
|
_Atomic(dns_namespace_t) nspace;
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
atomic_bool havensec;
|
2024-05-14 12:36:58 -07:00
|
|
|
atomic_bool wild;
|
|
|
|
atomic_bool delegating;
|
|
|
|
atomic_bool dirty;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *data;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
};
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
struct qpzonedb {
|
|
|
|
/* Unlocked. */
|
|
|
|
dns_db_t common;
|
|
|
|
/* Locks the data in this struct */
|
|
|
|
isc_rwlock_t lock;
|
2025-01-30 14:42:57 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: 'references' is NOT the global reference counter for
|
|
|
|
* the database object handled by dns_db_attach() and _detach();
|
|
|
|
* that one is 'common.references'.
|
|
|
|
*
|
|
|
|
* Instead, 'references' counts the number of nodes being used by
|
|
|
|
* at least one external caller. (It's called 'references' to
|
|
|
|
* leverage the ISC_REFCOUNT_STATIC macros, but 'nodes_in_use'
|
|
|
|
* might be a clearer name.)
|
|
|
|
*
|
|
|
|
* One additional reference to this counter is held by the database
|
|
|
|
* object itself. When 'common.references' goes to zero, that
|
|
|
|
* reference is released. When in turn 'references' goes to zero,
|
|
|
|
* the database is shut down and freed.
|
|
|
|
*/
|
|
|
|
isc_refcount_t references;
|
|
|
|
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *origin;
|
2025-05-26 11:34:16 +02:00
|
|
|
qpznode_t *nsec_origin;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *nsec3_origin;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_stats_t *gluecachestats;
|
2023-10-03 18:55:24 -07:00
|
|
|
/* Locked by lock. */
|
|
|
|
unsigned int attributes;
|
|
|
|
uint32_t current_serial;
|
|
|
|
uint32_t least_serial;
|
|
|
|
uint32_t next_serial;
|
2024-05-25 11:46:56 +02:00
|
|
|
uint32_t maxrrperset; /* Maximum RRs per RRset */
|
|
|
|
uint32_t maxtypepername; /* Maximum number of RR types per owner */
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *current_version;
|
|
|
|
qpz_version_t *future_version;
|
|
|
|
qpz_versionlist_t open_versions;
|
2023-10-03 18:55:24 -07:00
|
|
|
isc_loop_t *loop;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
struct rcu_head rcu_head;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
qpz_heap_t *heap; /* Resigning heap */
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_t *tree; /* QP trie for data storage */
|
2023-10-03 18:55:24 -07:00
|
|
|
};
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
#ifdef DNS_DB_NODETRACE
|
|
|
|
#define qpzonedb_ref(ptr) qpzonedb__ref(ptr, __func__, __FILE__, __LINE__)
|
2025-02-24 15:55:18 +01:00
|
|
|
#define qpzonedb_unref(ptr) qpzonedb__unref(ptr, __func__, __FILE__, __LINE__)
|
2025-01-27 21:07:11 +01:00
|
|
|
#define qpzonedb_attach(ptr, ptrp) \
|
|
|
|
qpzonedb__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
#define qpzonedb_detach(ptrp) \
|
|
|
|
qpzonedb__detach(ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
ISC_REFCOUNT_STATIC_TRACE_DECL(qpzonedb);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_STATIC_DECL(qpzonedb);
|
|
|
|
#endif
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*%
|
|
|
|
* Search Context
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
qpzonedb_t *qpdb;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_qpread_t qpr;
|
|
|
|
uint32_t serial;
|
|
|
|
unsigned int options;
|
|
|
|
dns_qpchain_t chain;
|
|
|
|
dns_qpiter_t iter;
|
|
|
|
bool copy_name;
|
|
|
|
bool need_cleanup;
|
|
|
|
bool wild;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *zonecut;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_t *zonecut_header;
|
|
|
|
dns_slabheader_t *zonecut_sigheader;
|
|
|
|
dns_fixedname_t zonecut_name;
|
2024-04-29 15:45:26 -07:00
|
|
|
} qpz_search_t;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*%
|
|
|
|
* Load Context
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
dns_db_t *db;
|
|
|
|
dns_qp_t *tree;
|
2024-04-29 15:45:26 -07:00
|
|
|
} qpz_load_t;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
static dns_dbmethods_t qpdb_zonemethods;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
static dns_dbnode_methods_t qpznode_methods;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
#if DNS_DB_NODETRACE
|
2024-04-29 15:29:33 -07:00
|
|
|
#define qpznode_ref(ptr) qpznode__ref(ptr, __func__, __FILE__, __LINE__)
|
|
|
|
#define qpznode_unref(ptr) qpznode__unref(ptr, __func__, __FILE__, __LINE__)
|
|
|
|
#define qpznode_attach(ptr, ptrp) \
|
|
|
|
qpznode__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
#define qpznode_detach(ptrp) qpznode__detach(ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
ISC_REFCOUNT_STATIC_TRACE_DECL(qpznode);
|
2023-10-03 18:55:24 -07:00
|
|
|
#else
|
2024-04-29 15:29:33 -07:00
|
|
|
ISC_REFCOUNT_STATIC_DECL(qpznode);
|
2023-10-03 18:55:24 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* QP trie methods */
|
|
|
|
static void
|
|
|
|
qp_attach(void *uctx, void *pval, uint32_t ival);
|
|
|
|
static void
|
|
|
|
qp_detach(void *uctx, void *pval, uint32_t ival);
|
|
|
|
static size_t
|
|
|
|
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
|
|
|
|
static void
|
|
|
|
qp_triename(void *uctx, char *buf, size_t size);
|
|
|
|
|
|
|
|
static dns_qpmethods_t qpmethods = {
|
|
|
|
qp_attach,
|
|
|
|
qp_detach,
|
|
|
|
qp_makekey,
|
|
|
|
qp_triename,
|
|
|
|
};
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
static void
|
|
|
|
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
|
|
|
|
static void
|
|
|
|
rdatasetiter_current(dns_rdatasetiter_t *iterator,
|
|
|
|
dns_rdataset_t *rdataset DNS__DB_FLARG);
|
|
|
|
|
|
|
|
static dns_rdatasetitermethods_t rdatasetiter_methods = {
|
|
|
|
rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
|
|
|
|
rdatasetiter_current
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct qpdb_rdatasetiter {
|
|
|
|
dns_rdatasetiter_t common;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *currenttop;
|
2023-11-15 08:55:18 -08:00
|
|
|
dns_slabheader_t *current;
|
|
|
|
} qpdb_rdatasetiter_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that these iterators, unless created with either DNS_DB_NSEC3ONLY
|
|
|
|
* or DNS_DB_NONSEC3, will transparently move between the last node of the
|
|
|
|
* "regular" QP trie and the root node of the NSEC3 QP trie of the database
|
|
|
|
* in question, as if the latter was a successor to the former in lexical
|
2025-05-26 11:34:16 +02:00
|
|
|
* order. The "current" field always holds the address of either "iter".
|
2023-11-15 08:55:18 -08:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_seek(dns_dbiterator_t *iterator,
|
|
|
|
const dns_name_t *name DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
|
|
|
|
dns_name_t *name DNS__DB_FLARG);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_pause(dns_dbiterator_t *iterator);
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
|
|
|
|
|
|
|
|
static dns_dbiteratormethods_t dbiterator_methods = {
|
|
|
|
dbiterator_destroy, dbiterator_first, dbiterator_last,
|
|
|
|
dbiterator_seek, dbiterator_prev, dbiterator_next,
|
|
|
|
dbiterator_current, dbiterator_pause, dbiterator_origin
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct qpdb_dbiterator {
|
|
|
|
dns_dbiterator_t common;
|
|
|
|
isc_result_t result;
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpsnap_t *snap; /* tree snapshot */
|
|
|
|
dns_qpiter_t iter; /* tree iterator */
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node;
|
2023-11-15 08:55:18 -08:00
|
|
|
enum { full, nonsec3, nsec3only } nsec3mode;
|
|
|
|
} qpdb_dbiterator_t;
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
/*%
|
|
|
|
* 'init_count' is used to initialize 'newheader->count' which inturn
|
|
|
|
* is used to determine where in the cycle rrset-order cyclic starts.
|
|
|
|
* We don't lock this as we don't care about simultaneous updates.
|
|
|
|
*/
|
|
|
|
static atomic_uint_fast16_t init_count = 0;
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
/*
|
|
|
|
* Locking
|
|
|
|
*
|
|
|
|
* If a routine is going to lock more than one lock in this module, then
|
|
|
|
* the locking must be done in the following order:
|
|
|
|
*
|
|
|
|
* Node Lock (Only one from the set may be locked at one time by
|
|
|
|
* any caller)
|
|
|
|
*
|
|
|
|
* Database Lock
|
|
|
|
*
|
|
|
|
* Failure to follow this hierarchy can result in deadlock.
|
|
|
|
*/
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
void
|
|
|
|
dns__qpzone_initialize(void) {
|
|
|
|
for (size_t idx = 0; idx < ARRAY_SIZE(qpzone_buckets_g); ++idx) {
|
|
|
|
NODE_INITLOCK(&qpzone_buckets_g[idx].lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns__qpzone_shutdown(void) {
|
|
|
|
for (size_t idx = 0; idx < ARRAY_SIZE(qpzone_buckets_g); ++idx) {
|
|
|
|
NODE_DESTROYLOCK(&qpzone_buckets_g[idx].lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-08 15:52:35 +02:00
|
|
|
static isc_rwlock_t *
|
2025-05-07 14:52:11 +02:00
|
|
|
qpzone_get_lock(qpznode_t *node) {
|
|
|
|
return &qpzone_buckets_g[node->locknum].lock;
|
2025-07-08 15:52:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
qpzone_get_locknum(void) {
|
2025-05-07 14:52:11 +02:00
|
|
|
return isc_random_uniform(ARRAY_SIZE(qpzone_buckets_g));
|
2025-07-08 15:52:35 +02:00
|
|
|
}
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
/*%
|
|
|
|
* 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 &&
|
2025-08-12 07:47:03 +02:00
|
|
|
h2->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_soa));
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* This function sets the heap index into the header.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
set_index(void *what, unsigned int idx) {
|
|
|
|
dns_slabheader_t *h = what;
|
|
|
|
|
|
|
|
h->heap_index = idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-12-05 13:45:24 +01:00
|
|
|
free_glue(isc_mem_t *mctx, dns_glue_t *glue) {
|
2024-12-03 15:07:30 +01:00
|
|
|
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);
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_name_free(&glue->name, mctx);
|
|
|
|
|
|
|
|
isc_mem_put(mctx, glue, sizeof(*glue));
|
2024-12-03 15:07:30 +01:00
|
|
|
|
|
|
|
glue = next;
|
|
|
|
}
|
|
|
|
}
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
static void
|
2024-12-05 13:45:24 +01:00
|
|
|
destroy_gluelist(dns_gluelist_t **gluelistp) {
|
|
|
|
REQUIRE(gluelistp != NULL);
|
|
|
|
if (*gluelistp == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_gluelist_t *gluelist = *gluelistp;
|
|
|
|
|
|
|
|
free_glue(gluelist->mctx, gluelist->glue);
|
2024-12-03 15:07:30 +01:00
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_gluelist_rcu(struct rcu_head *rcu_head) {
|
|
|
|
dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t,
|
|
|
|
rcu_head);
|
|
|
|
destroy_gluelist(&gluelist);
|
2024-12-03 15:07:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-12-05 13:45:24 +01:00
|
|
|
cleanup_gluelists(struct cds_wfs_stack *glue_stack) {
|
2024-12-03 15:07:30 +01:00
|
|
|
struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
|
|
|
|
struct cds_wfs_node *node = NULL, *next = NULL;
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
rcu_read_lock();
|
2024-12-03 15:07:30 +01:00
|
|
|
cds_wfs_for_each_blocking_safe(head, node, next) {
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_gluelist_t *gluelist =
|
|
|
|
caa_container_of(node, dns_gluelist_t, wfs_node);
|
|
|
|
dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header,
|
|
|
|
NULL);
|
|
|
|
(void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL);
|
2024-12-03 15:07:30 +01:00
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
call_rcu(&gluelist->rcu_head, free_gluelist_rcu);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
free_db_rcu(struct rcu_head *rcu_head) {
|
|
|
|
qpzonedb_t *qpdb = caa_container_of(rcu_head, qpzonedb_t, rcu_head);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
if (dns_name_dynamic(&qpdb->common.origin)) {
|
|
|
|
dns_name_free(&qpdb->common.origin, qpdb->common.mctx);
|
|
|
|
}
|
2025-07-08 16:29:56 +02:00
|
|
|
|
|
|
|
qpz_heap_detach(&qpdb->heap);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
if (qpdb->gluecachestats != NULL) {
|
|
|
|
isc_stats_detach(&qpdb->gluecachestats);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qpdb->loop != NULL) {
|
|
|
|
isc_loop_detach(&qpdb->loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_rwlock_destroy(&qpdb->lock);
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_refcount_destroy(&qpdb->references);
|
|
|
|
isc_refcount_destroy(&qpdb->common.references);
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
qpdb->common.magic = 0;
|
|
|
|
qpdb->common.impmagic = 0;
|
|
|
|
|
|
|
|
if (qpdb->common.update_listeners != NULL) {
|
|
|
|
INSIST(!cds_lfht_destroy(qpdb->common.update_listeners, NULL));
|
|
|
|
}
|
|
|
|
|
2025-07-08 15:52:35 +02:00
|
|
|
isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb));
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2025-01-27 21:07:11 +01:00
|
|
|
qpzone_destroy(qpzonedb_t *qpdb) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
REQUIRE(qpdb->future_version == NULL);
|
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
isc_refcount_decrementz(&qpdb->current_version->references);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
isc_refcount_destroy(&qpdb->current_version->references);
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_UNLINK(qpdb->open_versions, qpdb->current_version, link);
|
2024-12-03 15:07:30 +01:00
|
|
|
cds_wfs_destroy(&qpdb->current_version->glue_stack);
|
2024-03-12 11:32:29 -07:00
|
|
|
isc_rwlock_destroy(&qpdb->current_version->rwlock);
|
|
|
|
isc_mem_put(qpdb->common.mctx, qpdb->current_version,
|
|
|
|
sizeof(*qpdb->current_version));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
dns_qpmulti_destroy(&qpdb->tree);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
char buf[DNS_NAME_FORMATSIZE];
|
|
|
|
if (dns_name_dynamic(&qpdb->common.origin)) {
|
|
|
|
dns_name_format(&qpdb->common.origin, buf, sizeof(buf));
|
|
|
|
} else {
|
|
|
|
strlcpy(buf, "<UNKNOWN>", sizeof(buf));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
|
|
|
|
ISC_LOG_DEBUG(1), "called %s(%s)", __func__, buf);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
call_rcu(&qpdb->rcu_head, free_db_rcu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qpdb_destroy(dns_db_t *arg) {
|
2023-10-03 18:55:24 -07:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)arg;
|
|
|
|
|
|
|
|
if (qpdb->origin != NULL) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_detach(&qpdb->origin);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
if (qpdb->nsec_origin != NULL) {
|
|
|
|
qpznode_detach(&qpdb->nsec_origin);
|
|
|
|
}
|
2023-10-03 18:55:24 -07:00
|
|
|
if (qpdb->nsec3_origin != NULL) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_detach(&qpdb->nsec3_origin);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
2024-12-05 13:45:24 +01:00
|
|
|
cleanup_gluelists(&qpdb->current_version->glue_stack);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
qpzonedb_detach(&qpdb);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
static qpz_heap_t *
|
|
|
|
new_qpz_heap(isc_mem_t *mctx) {
|
|
|
|
qpz_heap_t *new_heap = isc_mem_get(mctx, sizeof(*new_heap));
|
|
|
|
*new_heap = (qpz_heap_t){
|
|
|
|
.references = ISC_REFCOUNT_INITIALIZER(1),
|
|
|
|
};
|
|
|
|
|
|
|
|
isc_mutex_init(&new_heap->lock);
|
|
|
|
isc_heap_create(mctx, resign_sooner, set_index, 0, &new_heap->heap);
|
|
|
|
isc_mem_attach(mctx, &new_heap->mctx);
|
|
|
|
|
|
|
|
return new_heap;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function accesses the heap lock through the header and node rather than
|
|
|
|
* directly through &qpdb->heap->lock to handle a critical race condition.
|
|
|
|
*
|
|
|
|
* Consider this scenario:
|
|
|
|
* 1. A reference is taken to a qpznode
|
|
|
|
* 2. The database containing that node is freed
|
|
|
|
* 3. The qpznode reference is finally released
|
|
|
|
*
|
|
|
|
* When the qpznode reference is released, it needs to unregister all its
|
|
|
|
* slabheaders from the resigning heap. The heap is a separate refcounted
|
|
|
|
* object with references from both the database and every qpznode. This
|
|
|
|
* design ensures that even after the database is destroyed, if nodes are
|
|
|
|
* still alive, the heap remains accessible for safe cleanup.
|
|
|
|
*
|
|
|
|
* Accessing the heap lock through the database (&qpdb->heap->lock) would
|
|
|
|
* cause a segfault in this scenario, even though the heap itself is still
|
|
|
|
* alive. By going through the node's heap reference, we maintain safe access
|
|
|
|
* to the heap lock regardless of the database's lifecycle.
|
|
|
|
*/
|
|
|
|
static isc_mutex_t *
|
|
|
|
get_heap_lock(dns_slabheader_t *header) {
|
|
|
|
return &HEADERNODE(header)->heap->lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qpz_heap_destroy(qpz_heap_t *qpheap) {
|
|
|
|
isc_mutex_destroy(&qpheap->lock);
|
|
|
|
isc_heap_destroy(&qpheap->heap);
|
|
|
|
isc_mem_putanddetach(&qpheap->mctx, qpheap, sizeof(*qpheap));
|
|
|
|
}
|
|
|
|
|
2024-04-29 15:29:33 -07:00
|
|
|
static qpznode_t *
|
2025-07-07 11:42:17 +02:00
|
|
|
new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
|
|
|
|
*newdata = (qpznode_t){
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
.methods = &qpznode_methods,
|
2024-03-11 18:47:01 -07:00
|
|
|
.name = DNS_NAME_INITEMPTY,
|
2025-07-07 11:42:17 +02:00
|
|
|
.nspace = nspace,
|
2025-07-08 16:29:56 +02:00
|
|
|
.heap = qpdb->heap,
|
2023-10-03 18:55:24 -07:00
|
|
|
.references = ISC_REFCOUNT_INITIALIZER(1),
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
.qpdb = qpdb,
|
2025-07-08 15:52:35 +02:00
|
|
|
.locknum = qpzone_get_locknum(),
|
2023-10-03 18:55:24 -07:00
|
|
|
};
|
2025-02-04 21:15:22 +01:00
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
|
2025-02-21 12:09:28 +01:00
|
|
|
dns_name_dup(name, qpdb->common.mctx, &newdata->name);
|
2025-07-08 16:29:56 +02:00
|
|
|
qpz_heap_ref(newdata->heap);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
#if DNS_DB_NODETRACE
|
2024-04-29 15:29:33 -07:00
|
|
|
fprintf(stderr, "new_qpznode:%s:%s:%d:%p->references = 1\n", __func__,
|
2023-10-03 18:55:24 -07:00
|
|
|
__FILE__, __LINE__ + 1, name);
|
|
|
|
#endif
|
|
|
|
return newdata;
|
|
|
|
}
|
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
static qpz_version_t *
|
2023-10-03 18:55:24 -07:00
|
|
|
allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references,
|
|
|
|
bool writer) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version = isc_mem_get(mctx, sizeof(*version));
|
|
|
|
*version = (qpz_version_t){
|
2023-10-03 18:55:24 -07:00
|
|
|
.serial = serial,
|
|
|
|
.writer = writer,
|
|
|
|
.changed_list = ISC_LIST_INITIALIZER,
|
|
|
|
.resigned_list = ISC_LIST_INITIALIZER,
|
|
|
|
.link = ISC_LINK_INITIALIZER,
|
2025-01-27 21:07:11 +01:00
|
|
|
.references = ISC_REFCOUNT_INITIALIZER(references),
|
2023-10-03 18:55:24 -07:00
|
|
|
};
|
|
|
|
|
2024-12-03 15:07:30 +01:00
|
|
|
cds_wfs_init(&version->glue_stack);
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlock_init(&version->rwlock);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
|
|
|
dns_rdataclass_t rdclass, unsigned int argc ISC_ATTR_UNUSED,
|
|
|
|
char **argv ISC_ATTR_UNUSED, void *driverarg ISC_ATTR_UNUSED,
|
|
|
|
dns_db_t **dbp) {
|
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_qp_t *qp = NULL;
|
|
|
|
|
2025-07-08 15:52:35 +02:00
|
|
|
qpdb = isc_mem_get(mctx, sizeof(*qpdb));
|
2023-10-03 18:55:24 -07:00
|
|
|
*qpdb = (qpzonedb_t){
|
|
|
|
.common.origin = DNS_NAME_INITEMPTY,
|
|
|
|
.common.rdclass = rdclass,
|
2025-01-27 21:07:11 +01:00
|
|
|
.common.references = ISC_REFCOUNT_INITIALIZER(1),
|
2023-10-03 18:55:24 -07:00
|
|
|
.current_serial = 1,
|
|
|
|
.least_serial = 1,
|
|
|
|
.next_serial = 2,
|
|
|
|
.open_versions = ISC_LIST_INITIALIZER,
|
2025-01-27 21:07:11 +01:00
|
|
|
.references = ISC_REFCOUNT_INITIALIZER(1),
|
2023-10-03 18:55:24 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
qpdb->common.methods = &qpdb_zonemethods;
|
|
|
|
if (type == dns_dbtype_stub) {
|
|
|
|
qpdb->common.attributes |= DNS_DBATTR_STUB;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_rwlock_init(&qpdb->lock);
|
|
|
|
|
|
|
|
qpdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL);
|
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
qpdb->heap = new_qpz_heap(mctx);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Attach to the mctx. The database will persist so long as there
|
|
|
|
* are references to it, and attaching to the mctx ensures that our
|
|
|
|
* mctx won't disappear out from under us.
|
|
|
|
*/
|
|
|
|
isc_mem_attach(mctx, &qpdb->common.mctx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a copy of the origin name.
|
|
|
|
*/
|
2025-02-21 12:09:28 +01:00
|
|
|
dns_name_dup(origin, mctx, &qpdb->common.origin);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->tree);
|
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
/*
|
|
|
|
* Version initialization.
|
|
|
|
*/
|
|
|
|
qpdb->current_version = allocate_version(mctx, 1, 1, false);
|
|
|
|
qpdb->current_version->qpdb = qpdb;
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_write(qpdb->tree, &qp);
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
/*
|
|
|
|
* 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 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 data's address.
|
|
|
|
*/
|
2025-07-07 11:42:17 +02:00
|
|
|
qpdb->origin = new_qpznode(qpdb, &qpdb->common.origin,
|
|
|
|
DNS_DBNAMESPACE_NORMAL);
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
result = dns_qp_insert(qp, qpdb->origin, 0);
|
2025-02-11 16:08:29 -08:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an apex node to the NSEC tree so that we can quickly skip over
|
|
|
|
* the NSEC nodes while iterating over the full tree.
|
|
|
|
*/
|
2025-07-07 11:42:17 +02:00
|
|
|
qpdb->nsec_origin = new_qpznode(qpdb, &qpdb->common.origin,
|
|
|
|
DNS_DBNAMESPACE_NSEC);
|
2025-05-26 11:34:16 +02:00
|
|
|
result = dns_qp_insert(qp, qpdb->nsec_origin, 0);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-07-07 11:42:17 +02:00
|
|
|
qpdb->nsec3_origin = new_qpznode(qpdb, &qpdb->common.origin,
|
|
|
|
DNS_DBNAMESPACE_NSEC3);
|
2023-10-03 18:55:24 -07:00
|
|
|
result = dns_qp_insert(qp, qpdb->nsec3_origin, 0);
|
2025-02-11 16:08:29 -08:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
dns_qpmulti_commit(qpdb->tree, &qp);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep the current version in the open list so that list operation
|
|
|
|
* won't happen in normal lookup operations.
|
|
|
|
*/
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_PREPEND(qpdb->open_versions, qpdb->current_version, link);
|
2023-10-03 18:55:24 -07:00
|
|
|
|
|
|
|
qpdb->common.magic = DNS_DB_MAGIC;
|
|
|
|
qpdb->common.impmagic = QPZONE_DB_MAGIC;
|
|
|
|
|
|
|
|
*dbp = (dns_db_t *)qpdb;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
/*
|
|
|
|
* If incrementing erefs from zero, we also increment the node use counter
|
|
|
|
* in the qpzonedb object.
|
|
|
|
*
|
|
|
|
* This function is called from qpznode_acquire(), so that internal
|
|
|
|
* and external references are acquired at the same time, and from
|
|
|
|
* qpznode_release() when we only need to increase the internal references.
|
|
|
|
*/
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_erefs_increment(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
|
2025-01-17 16:54:19 -08:00
|
|
|
uint_fast32_t refs = isc_refcount_increment0(&node->erefs);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
#if DNS_DB_NODETRACE
|
2023-12-02 01:04:28 -08:00
|
|
|
fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
func, file, line, node, refs + 1);
|
|
|
|
#endif
|
|
|
|
|
2025-01-27 18:06:17 +01:00
|
|
|
if (refs > 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
qpzonedb_ref(qpdb);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2023-10-03 18:55:24 -07:00
|
|
|
|
2025-01-17 16:54:19 -08:00
|
|
|
static void
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
|
2025-01-17 16:54:19 -08:00
|
|
|
qpznode_ref(node);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_erefs_increment(qpdb, node DNS__DB_FLARG_PASS);
|
2025-01-17 16:54:19 -08:00
|
|
|
}
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
static void
|
2024-04-29 15:29:33 -07:00
|
|
|
clean_zone_node(qpznode_t *node, uint32_t least_serial) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool still_dirty = false;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_db_t *db = (dns_db_t *)node->qpdb;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Caller must be holding the node lock.
|
|
|
|
*/
|
|
|
|
REQUIRE(least_serial != 0);
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top_next) {
|
|
|
|
top_next = top->next;
|
|
|
|
|
|
|
|
INSIST(top->header != NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First, we clean up any instances of multiple rdatasets
|
|
|
|
* with the same serial number, or that have the IGNORE
|
|
|
|
* attribute.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *dcurrent = NULL;
|
|
|
|
dns_slabheader_t *dcurrent_down = NULL, *dparent = NULL;
|
|
|
|
|
|
|
|
dparent = top->header;
|
|
|
|
for (dcurrent = dparent->down; dcurrent != NULL;
|
2025-01-31 15:47:33 +01:00
|
|
|
dcurrent = dcurrent_down)
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
2025-01-31 15:47:33 +01:00
|
|
|
dcurrent_down = dcurrent->down;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
INSIST(dcurrent->serial <= dparent->serial);
|
|
|
|
if (dcurrent->serial == dparent->serial ||
|
|
|
|
IGNORE(dcurrent))
|
|
|
|
{
|
2025-01-31 15:47:33 +01:00
|
|
|
dparent->down = dcurrent_down;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_destroy(&dcurrent);
|
|
|
|
} else {
|
|
|
|
dparent = dcurrent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We've now eliminated all IGNORE datasets with the possible
|
|
|
|
* exception of current, which we now check.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
dcurrent = top->header;
|
2025-01-31 15:47:33 +01:00
|
|
|
if (IGNORE(dcurrent)) {
|
2025-08-05 18:05:52 +02:00
|
|
|
top->header = dcurrent->down;
|
|
|
|
dns_slabheader_destroy(&dcurrent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (top->header == NULL) {
|
|
|
|
goto empty;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2025-08-05 18:05:52 +02:00
|
|
|
* We now try to find the first down node less than the least
|
|
|
|
* serial, and if there are such rdatasets, delete it and any
|
|
|
|
* older versions.
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
dparent = top->header;
|
|
|
|
for (dcurrent = dparent->down; dcurrent != NULL;
|
2025-01-31 15:47:33 +01:00
|
|
|
dcurrent = dcurrent_down)
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
2025-01-31 15:47:33 +01:00
|
|
|
dcurrent_down = dcurrent->down;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (dcurrent->serial < least_serial) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dparent->down = dcurrent_down;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_destroy(&dcurrent);
|
2025-08-05 18:05:52 +02:00
|
|
|
} else {
|
|
|
|
dparent = dcurrent;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->header == NULL) {
|
|
|
|
empty:
|
|
|
|
if (top_prev != NULL) {
|
|
|
|
top_prev->next = top->next;
|
|
|
|
} else {
|
|
|
|
node->data = top->next;
|
|
|
|
}
|
|
|
|
dns_slabtop_destroy(db->mctx, &top);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
still_dirty = true;
|
2025-08-05 18:05:52 +02:00
|
|
|
top_prev = top;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!still_dirty) {
|
2024-05-14 12:36:58 -07:00
|
|
|
node->dirty = false;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
/*
|
|
|
|
* Decrement the external references to a node. If the counter
|
|
|
|
* goes to zero, decrement the node use counter in the qpzonedb object
|
|
|
|
* as well, and return true. Otherwise return false.
|
|
|
|
*/
|
2025-01-27 18:06:17 +01:00
|
|
|
static bool
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_erefs_decrement(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
|
2025-01-27 18:06:17 +01:00
|
|
|
uint_fast32_t refs = isc_refcount_decrement(&node->erefs);
|
|
|
|
|
|
|
|
#if DNS_DB_NODETRACE
|
|
|
|
fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
|
|
|
|
func, file, line, node, refs - 1);
|
|
|
|
#endif
|
|
|
|
if (refs > 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
qpzonedb_unref(qpdb);
|
2025-01-27 18:06:17 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* Caller must be holding the node lock; either the read or write lock.
|
|
|
|
* Note that the lock must be held even when node references are
|
|
|
|
* atomically modified; in that case the decrement operation itself does not
|
|
|
|
* have to be protected, but we must avoid a race condition where multiple
|
|
|
|
* threads are decreasing the reference to zero simultaneously and at least
|
|
|
|
* one of them is going to free the node.
|
|
|
|
*
|
2025-01-30 14:42:57 -08:00
|
|
|
* This calls dec_erefs() to decrement the external node reference counter,
|
|
|
|
* (and possibly the node use counter), cleans up and deletes the node
|
|
|
|
* if necessary, then decrements the internal reference counter as well.
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
*/
|
2023-12-02 01:04:28 -08:00
|
|
|
static void
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(qpzonedb_t *qpdb, qpznode_t *node, uint32_t least_serial,
|
|
|
|
isc_rwlocktype_t *nlocktypep DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
REQUIRE(*nlocktypep != isc_rwlocktype_none);
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
if (!qpznode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
|
2025-01-27 18:06:17 +01:00
|
|
|
goto unref;
|
2025-01-17 16:54:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle easy and typical case first. */
|
2025-08-19 14:12:46 +02:00
|
|
|
if (!node->dirty && node->data != NULL) {
|
2025-01-27 18:06:17 +01:00
|
|
|
goto unref;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*nlocktypep == isc_rwlocktype_read) {
|
2025-01-30 14:42:57 -08:00
|
|
|
/*
|
|
|
|
* The external reference count went to zero and the node
|
|
|
|
* is dirty or has no data, so we might want to delete it.
|
|
|
|
* To do that, we'll need a write lock. If we don't already
|
|
|
|
* have one, we have to make sure nobody else has
|
|
|
|
* acquired a reference in the meantime, so we increment
|
|
|
|
* erefs (but NOT references!), upgrade the node lock,
|
|
|
|
* decrement erefs again, and see if it's still zero.
|
2025-02-24 15:55:18 +01:00
|
|
|
*
|
|
|
|
* We can't really assume anything about the result code of
|
|
|
|
* erefs_increment. If another thread acquires reference it
|
|
|
|
* will be larger than 0, if it doesn't it is going to be 0.
|
2025-01-30 14:42:57 -08:00
|
|
|
*/
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_erefs_increment(qpdb, node DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_FORCEUPGRADE(nlock, nlocktypep);
|
2025-01-30 14:42:57 -08:00
|
|
|
if (!qpznode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
|
|
|
|
goto unref;
|
|
|
|
}
|
2025-01-17 16:54:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (node->dirty) {
|
|
|
|
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);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-01-17 16:54:19 -08:00
|
|
|
clean_zone_node(node, least_serial);
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 18:06:17 +01:00
|
|
|
unref:
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_unref(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-29 15:29:33 -07:00
|
|
|
bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header,
|
2025-02-03 14:06:37 +01:00
|
|
|
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (rdataset == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
INSIST(rdataset->methods == NULL); /* We must be disassociated. */
|
|
|
|
|
|
|
|
rdataset->methods = &dns_rdataslab_rdatasetmethods;
|
|
|
|
rdataset->rdclass = qpdb->common.rdclass;
|
2025-08-06 19:34:35 +02:00
|
|
|
rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair);
|
|
|
|
rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair);
|
2025-02-03 14:06:37 +01:00
|
|
|
rdataset->ttl = header->ttl;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
rdataset->trust = header->trust;
|
|
|
|
|
|
|
|
if (OPTOUT(header)) {
|
2025-07-09 16:56:22 +02:00
|
|
|
rdataset->attributes.optout = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
rdataset->count = atomic_fetch_add_relaxed(&header->count, 1);
|
|
|
|
|
|
|
|
rdataset->slab.db = (dns_db_t *)qpdb;
|
|
|
|
rdataset->slab.node = (dns_dbnode_t *)node;
|
2025-08-17 15:54:03 -07:00
|
|
|
rdataset->slab.raw = header->raw;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
rdataset->slab.iter_pos = NULL;
|
|
|
|
rdataset->slab.iter_count = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add noqname proof.
|
|
|
|
*/
|
|
|
|
rdataset->slab.noqname = header->noqname;
|
|
|
|
if (header->noqname != NULL) {
|
2025-07-09 16:56:22 +02:00
|
|
|
rdataset->attributes.noqname = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
rdataset->slab.closest = header->closest;
|
|
|
|
if (header->closest != NULL) {
|
2025-07-09 16:56:22 +02:00
|
|
|
rdataset->attributes.closest = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy out re-signing information.
|
|
|
|
*/
|
|
|
|
if (RESIGN(header)) {
|
2025-07-09 16:56:22 +02:00
|
|
|
rdataset->attributes.resign = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
rdataset->resign = (header->resign << 1) | header->resign_lsb;
|
|
|
|
} else {
|
|
|
|
rdataset->resign = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
setnsec3parameters(dns_db_t *db, qpz_version_t *version) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_rdata_nsec3param_t nsec3param;
|
|
|
|
isc_region_t region;
|
|
|
|
isc_result_t result;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
unsigned char *raw; /* RDATASLAB */
|
|
|
|
unsigned int count, length;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *found = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
version->havensec3 = false;
|
|
|
|
node = qpdb->origin;
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-08-05 18:05:52 +02:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
top = node->data;
|
|
|
|
while (top != NULL && top->typepair != dns_rdatatype_nsec3param) {
|
|
|
|
top = top->next;
|
|
|
|
}
|
|
|
|
if (top != NULL) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
while (header != NULL &&
|
|
|
|
(IGNORE(header) || header->serial > version->serial))
|
2023-11-19 00:00:49 -08:00
|
|
|
{
|
2025-08-05 18:05:52 +02:00
|
|
|
header = header->down;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header != NULL && EXISTS(header)) {
|
|
|
|
found = header;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found != NULL) {
|
|
|
|
/*
|
|
|
|
* Find an NSEC3PARAM with a supported algorithm.
|
|
|
|
*/
|
2025-08-17 15:54:03 -07:00
|
|
|
raw = found->raw;
|
2025-08-17 13:59:05 -07:00
|
|
|
count = get_uint16(raw);
|
2025-08-05 18:05:52 +02:00
|
|
|
while (count-- > 0U) {
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2025-08-17 13:59:05 -07:00
|
|
|
|
|
|
|
length = get_uint16(raw);
|
2025-08-05 18:05:52 +02:00
|
|
|
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);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG &&
|
|
|
|
!dns_nsec3_supportedhash(nsec3param.hash))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (nsec3param.flags != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
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;
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock:
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
cleanup_nondirty(qpz_version_t *version, qpz_changedlist_t *cleanup_list) {
|
2023-11-19 00:00:49 -08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(version->changed_list, changed, link) {
|
2023-11-19 00:00:49 -08:00
|
|
|
if (!changed->dirty) {
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_UNLINK(version->changed_list, changed, link);
|
|
|
|
ISC_LIST_APPEND(*cleanup_list, changed, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_rdataset_t keyset;
|
|
|
|
dns_rdataset_t nsecset, signsecset;
|
|
|
|
bool haszonekey = false;
|
|
|
|
bool hasnsec = false;
|
|
|
|
isc_result_t result;
|
|
|
|
|
2025-03-13 13:01:47 -07:00
|
|
|
version->secure = false;
|
|
|
|
version->havensec3 = false;
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_rdataset_init(&keyset);
|
2024-11-05 18:50:15 +01:00
|
|
|
result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
|
|
|
|
dns_rdatatype_dnskey, 0, 0, &keyset, NULL);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2025-03-13 13:01:47 -07:00
|
|
|
haszonekey = dns_dnssec_haszonekey(&keyset);
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_rdataset_disassociate(&keyset);
|
|
|
|
}
|
|
|
|
if (!haszonekey) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_rdataset_init(&nsecset);
|
|
|
|
dns_rdataset_init(&signsecset);
|
2024-11-05 18:50:15 +01:00
|
|
|
result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
|
|
|
|
dns_rdatatype_nsec, 0, 0, &nsecset,
|
|
|
|
&signsecset);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (dns_rdataset_isassociated(&signsecset)) {
|
|
|
|
hasnsec = true;
|
|
|
|
dns_rdataset_disassociate(&signsecset);
|
|
|
|
}
|
|
|
|
dns_rdataset_disassociate(&nsecset);
|
|
|
|
}
|
|
|
|
|
|
|
|
setnsec3parameters(db, version);
|
|
|
|
|
|
|
|
/*
|
2025-03-13 13:01:47 -07:00
|
|
|
* If we don't have a valid NSEC/NSEC3 chain,
|
|
|
|
* clear the secure flag.
|
2023-11-19 00:00:49 -08:00
|
|
|
*/
|
|
|
|
if (version->havensec3 || hasnsec) {
|
|
|
|
version->secure = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
|
|
|
currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(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;
|
|
|
|
}
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
static void
|
|
|
|
attachversion(dns_db_t *db, dns_dbversion_t *source,
|
|
|
|
dns_dbversion_t **targetp) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)source;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
INSIST(version != NULL && version->qpdb == qpdb);
|
|
|
|
|
|
|
|
isc_refcount_increment(&version->references);
|
|
|
|
|
2024-11-05 18:50:15 +01:00
|
|
|
*targetp = source;
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static isc_result_t
|
|
|
|
newversion(dns_db_t *db, dns_dbversion_t **versionp) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2023-11-19 00:00:49 -08:00
|
|
|
REQUIRE(versionp != NULL && *versionp == NULL);
|
|
|
|
REQUIRE(qpdb->future_version == NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
INSIST(qpdb->next_serial != 0);
|
|
|
|
version = allocate_version(qpdb->common.mctx, qpdb->next_serial, 1,
|
|
|
|
true);
|
|
|
|
version->qpdb = qpdb;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
version->records = qpdb->current_version->records;
|
|
|
|
version->xfrsize = qpdb->current_version->xfrsize;
|
|
|
|
|
|
|
|
qpdb->next_serial++;
|
|
|
|
qpdb->future_version = version;
|
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2024-11-05 18:50:15 +01:00
|
|
|
*versionp = (dns_dbversion_t *)version;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(dns_slabheader_t *newheader) {
|
2024-03-25 17:23:19 -07:00
|
|
|
REQUIRE(newheader->heap_index == 0);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
LOCK(get_heap_lock(newheader));
|
|
|
|
isc_heap_insert(HEADERNODE(newheader)->heap->heap, newheader);
|
|
|
|
UNLOCK(get_heap_lock(newheader));
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
resigndelete(qpzonedb_t *qpdb ISC_ATTR_UNUSED, qpz_version_t *version,
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_slabheader_t *header DNS__DB_FLARG) {
|
2024-03-25 17:23:19 -07:00
|
|
|
if (header == NULL || header->heap_index == 0) {
|
|
|
|
return;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2024-03-25 17:23:19 -07:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
LOCK(get_heap_lock(header));
|
|
|
|
isc_heap_delete(HEADERNODE(header)->heap->heap, header->heap_index);
|
|
|
|
UNLOCK(get_heap_lock(header));
|
2024-03-25 17:23:19 -07:00
|
|
|
|
|
|
|
header->heap_index = 0;
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, HEADERNODE(header) DNS__DB_FLARG_PASS);
|
2025-08-13 09:30:45 +02:00
|
|
|
|
|
|
|
qpz_resigned_t *resigned = isc_mem_get(((dns_db_t *)qpdb)->mctx,
|
|
|
|
sizeof(*resigned));
|
|
|
|
*resigned = (qpz_resigned_t){
|
|
|
|
.header = header,
|
|
|
|
.link = ISC_LINK_INITIALIZER,
|
|
|
|
};
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(version->resigned_list, resigned, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
make_least_version(qpzonedb_t *qpdb, qpz_version_t *version,
|
|
|
|
qpz_changedlist_t *cleanup_list) {
|
2023-11-19 00:00:49 -08:00
|
|
|
qpdb->least_serial = version->serial;
|
|
|
|
*cleanup_list = version->changed_list;
|
|
|
|
ISC_LIST_INIT(version->changed_list);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static void
|
2024-04-29 15:29:33 -07:00
|
|
|
rollback_node(qpznode_t *node, uint32_t serial) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
bool make_dirty = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
if (header->serial == serial) {
|
|
|
|
DNS_SLABHEADER_SETATTR(header,
|
|
|
|
DNS_SLABHEADERATTR_IGNORE);
|
|
|
|
make_dirty = true;
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
|
|
|
|
for (header = header->down; header != NULL;
|
|
|
|
header = header->down)
|
2023-11-19 00:00:49 -08:00
|
|
|
{
|
2025-08-05 18:05:52 +02:00
|
|
|
if (header->serial == serial) {
|
2023-11-19 00:00:49 -08:00
|
|
|
DNS_SLABHEADER_SETATTR(
|
2025-08-05 18:05:52 +02:00
|
|
|
header, DNS_SLABHEADERATTR_IGNORE);
|
2023-11-19 00:00:49 -08:00
|
|
|
make_dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (make_dirty) {
|
2024-05-14 12:36:58 -07:00
|
|
|
node->dirty = true;
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
closeversion(dns_db_t *db, dns_dbversion_t **versionp,
|
|
|
|
bool commit DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version = NULL, *cleanup_version = NULL;
|
|
|
|
qpz_version_t *least_greater = NULL;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
bool rollback = false;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_changedlist_t cleanup_list;
|
2025-08-13 09:30:45 +02:00
|
|
|
qpz_resignedlist_t resigned_list;
|
2023-11-19 00:00:49 -08:00
|
|
|
uint32_t serial, least_serial;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2024-04-29 15:45:26 -07:00
|
|
|
version = (qpz_version_t *)*versionp;
|
2023-11-19 00:00:49 -08:00
|
|
|
INSIST(version->qpdb == qpdb);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
if (isc_refcount_decrement(&version->references) > 1) {
|
|
|
|
*versionp = NULL;
|
|
|
|
return;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
ISC_LIST_INIT(cleanup_list);
|
|
|
|
ISC_LIST_INIT(resigned_list);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
/*
|
|
|
|
* Update the zone's secure status in version before making
|
|
|
|
* it the current version.
|
|
|
|
*/
|
|
|
|
if (version->writer && commit) {
|
2024-11-05 16:13:10 +01:00
|
|
|
setsecure(db, version, (dns_dbnode_t *)qpdb->origin);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
serial = version->serial;
|
|
|
|
if (version->writer) {
|
|
|
|
if (commit) {
|
|
|
|
unsigned int cur_ref;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *cur_version = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
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) {
|
2025-02-28 21:04:21 +01:00
|
|
|
INSIST(ISC_LIST_EMPTY(
|
2023-11-19 00:00:49 -08:00
|
|
|
cur_version->changed_list));
|
|
|
|
}
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_UNLINK(qpdb->open_versions,
|
|
|
|
cur_version, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
2025-02-28 21:04:21 +01:00
|
|
|
if (ISC_LIST_EMPTY(qpdb->open_versions)) {
|
2023-11-19 00:00:49 -08:00
|
|
|
/*
|
|
|
|
* 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;
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_APPENDLIST(
|
|
|
|
version->changed_list,
|
|
|
|
cleanup_version->changed_list, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* 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);
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_PREPEND(qpdb->open_versions,
|
|
|
|
qpdb->current_version, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
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.
|
|
|
|
*/
|
2025-02-28 21:04:21 +01:00
|
|
|
least_greater = ISC_LIST_PREV(version, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
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.
|
|
|
|
*/
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_APPENDLIST(least_greater->changed_list,
|
|
|
|
version->changed_list,
|
|
|
|
link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
} else if (version->serial == qpdb->least_serial) {
|
2025-02-28 21:04:21 +01:00
|
|
|
INSIST(ISC_LIST_EMPTY(version->changed_list));
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
2025-02-28 21:04:21 +01:00
|
|
|
ISC_LIST_UNLINK(qpdb->open_versions, version, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
least_serial = qpdb->least_serial;
|
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
|
|
|
|
if (cleanup_version != NULL) {
|
|
|
|
isc_refcount_destroy(&cleanup_version->references);
|
2025-02-28 21:04:21 +01:00
|
|
|
INSIST(ISC_LIST_EMPTY(cleanup_version->changed_list));
|
2024-12-05 13:45:24 +01:00
|
|
|
cleanup_gluelists(&cleanup_version->glue_stack);
|
2024-12-03 15:07:30 +01:00
|
|
|
cds_wfs_destroy(&cleanup_version->glue_stack);
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlock_destroy(&cleanup_version->rwlock);
|
|
|
|
isc_mem_put(qpdb->common.mctx, cleanup_version,
|
|
|
|
sizeof(*cleanup_version));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Commit/rollback re-signed headers.
|
|
|
|
*/
|
2025-08-13 09:30:45 +02:00
|
|
|
ISC_LIST_FOREACH(resigned_list, resigned, link) {
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-08-13 09:30:45 +02:00
|
|
|
dns_slabheader_t *header = resigned->header;
|
|
|
|
|
|
|
|
ISC_LIST_UNLINK(resigned_list, resigned, link);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-13 09:30:45 +02:00
|
|
|
isc_mem_put(db->mctx, resigned, sizeof(*resigned));
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(HEADERNODE(header));
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (rollback && !IGNORE(header)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(header);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(qpdb, HEADERNODE(header), least_serial,
|
|
|
|
&nlocktype DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
2025-03-05 17:36:53 +01:00
|
|
|
if (ISC_LIST_EMPTY(cleanup_list)) {
|
|
|
|
*versionp = NULL;
|
|
|
|
return;
|
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(cleanup_list, changed, link) {
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
|
|
|
|
|
|
|
node = changed->node;
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (rollback) {
|
|
|
|
rollback_node(node, serial);
|
|
|
|
}
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(qpdb, node, least_serial,
|
|
|
|
&nlocktype DNS__DB_FILELINE);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
isc_mem_put(qpdb->common.mctx, changed, sizeof(*changed));
|
|
|
|
}
|
|
|
|
|
|
|
|
*versionp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
|
|
|
dns_dbversion_t *dbversion, dns_rdatatype_t type,
|
|
|
|
dns_rdatatype_t covers, isc_stdtime_t now ISC_ATTR_UNUSED,
|
|
|
|
dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
2023-11-19 00:00:49 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_slabheader_t *found = NULL, *foundsig = NULL;
|
|
|
|
uint32_t serial;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2023-11-19 00:00:49 -08:00
|
|
|
bool close_version = false;
|
2025-08-06 19:34:35 +02:00
|
|
|
dns_typepair_t typepair, sigpair;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(type != dns_rdatatype_any);
|
|
|
|
INSIST(version == NULL || version->qpdb == qpdb);
|
|
|
|
|
2025-08-07 08:08:24 +02:00
|
|
|
if (type == dns_rdatatype_none && covers == dns_rdatatype_none) {
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
if (version == NULL) {
|
|
|
|
currentversion(db, (dns_dbversion_t **)&version);
|
|
|
|
close_version = true;
|
|
|
|
}
|
|
|
|
serial = version->serial;
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-06 19:34:35 +02:00
|
|
|
typepair = DNS_TYPEPAIR_VALUE(type, covers);
|
2025-08-11 07:17:43 +02:00
|
|
|
if (covers == dns_rdatatype_none) {
|
2025-08-12 07:47:03 +02:00
|
|
|
sigpair = DNS_SIGTYPEPAIR(type);
|
2023-11-19 00:00:49 -08:00
|
|
|
} else {
|
Remove the negative type logic from qpcache
Previously, when a negative header was stored in the cache, it would be
stored in the dns_typepair_t as .type = 0, .covers = <negative type>.
When searching the cache internally, we would have to look for both
positive and negative typepair and the slabheader .down list could be a
mix of positive and negative types.
Remove the extra representation of the negative type and simply use the
negative attribute on the slabheader. Other units (namely dns_ncache)
can still insert the (0, type) negative rdatasets into the cache, but
internally, those will be converted into (type, 0) slabheaders, and vice
versa - when binding the rdatasets, the negative (type, 0) slabheader
will be converted to (0, type) rdataset. Simple DNS_TYPEPAIR() helper
macro was added to simplify converting single rdatatype to typepair
value.
As a side-effect, the search logic in all places can exit early if
there's a negative header for the type we are looking for, f.e. when
searching for the zone cut, we don't have to walk through all the
slabheaders, if there's a stored negative slabheader.
2025-08-11 09:39:13 +02:00
|
|
|
sigpair = dns_typepair_none;
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
2023-11-19 00:00:49 -08:00
|
|
|
do {
|
|
|
|
if (header->serial <= serial && !IGNORE(header)) {
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
2023-11-19 00:00:49 -08:00
|
|
|
header = NULL;
|
|
|
|
}
|
|
|
|
break;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} 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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair == typepair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
found = header;
|
|
|
|
if (foundsig != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair == sigpair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
foundsig = header;
|
|
|
|
if (found != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found != NULL) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(qpdb, node, found, rdataset DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (foundsig != NULL) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(qpdb, node, foundsig,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
sigrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if (close_version) {
|
|
|
|
closeversion(db, (dns_dbversion_t **)&version,
|
|
|
|
false DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == NULL) {
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2025-08-06 19:34:35 +02:00
|
|
|
delegating_type(qpzonedb_t *qpdb, qpznode_t *node, dns_typepair_t typepair) {
|
2025-08-05 18:05:52 +02:00
|
|
|
return typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
|
|
|
|
(typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
(node != qpdb->origin || IS_STUB(qpdb)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
loading_addnode(qpz_load_t *loadctx, const dns_name_t *name,
|
2024-02-05 16:11:16 -08:00
|
|
|
dns_rdatatype_t type, dns_rdatatype_t covers,
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t **nodep) {
|
2024-02-05 16:11:16 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL, *nsecnode = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if (type == dns_rdatatype_nsec3 || covers == dns_rdatatype_nsec3) {
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_getname(loadctx->tree, name,
|
|
|
|
DNS_DBNAMESPACE_NSEC3, (void **)&node,
|
|
|
|
NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
*nodep = node;
|
|
|
|
} else {
|
2025-07-07 11:42:17 +02:00
|
|
|
node = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NSEC3);
|
2025-05-26 11:34:16 +02:00
|
|
|
result = dns_qp_insert(loadctx->tree, node, 0);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
*nodep = node;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_detach(&node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_getname(loadctx->tree, name, DNS_DBNAMESPACE_NORMAL,
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
(void **)&node, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
if (type == dns_rdatatype_nsec && node->havensec) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
INSIST(node == NULL);
|
2025-07-07 11:42:17 +02:00
|
|
|
node = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NORMAL);
|
2024-02-05 16:11:16 -08:00
|
|
|
result = dns_qp_insert(loadctx->tree, node, 0);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_unref(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
if (type != dns_rdatatype_nsec) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're adding an NSEC record, so create a node in the nsec tree
|
|
|
|
* too. This tree speeds searches for closest NSECs that would
|
|
|
|
* otherwise need to examine many irrelevant nodes in large TLDs.
|
2025-02-11 16:08:29 -08:00
|
|
|
* If dns_qp_insert() fails, it means there's already an NSEC
|
|
|
|
* node there, so we can just detach the new one we created and
|
|
|
|
* move on.
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
*/
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
node->havensec = true;
|
2025-07-07 11:42:17 +02:00
|
|
|
nsecnode = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NSEC);
|
2025-05-26 11:34:16 +02:00
|
|
|
(void)dns_qp_insert(loadctx->tree, nsecnode, 0);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_detach(&nsecnode);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
done:
|
|
|
|
*nodep = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2024-04-29 15:29:33 -07:00
|
|
|
cname_and_other(qpznode_t *node, uint32_t serial) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool cname = false, other = false;
|
|
|
|
dns_rdatatype_t rdtype;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for CNAME and "other data" rdatasets active in our version.
|
|
|
|
* ("Other data" is any rdataset whose type is not KEY, NSEC, SIG
|
|
|
|
* or RRSIG.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
rdtype = DNS_TYPEPAIR_TYPE(top->typepair);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (rdtype == dns_rdatatype_cname) {
|
|
|
|
do {
|
|
|
|
if (header->serial <= serial && !IGNORE(header))
|
|
|
|
{
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
header = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
header = header->down;
|
|
|
|
} while (header != NULL);
|
|
|
|
if (header != NULL) {
|
|
|
|
cname = true;
|
|
|
|
}
|
|
|
|
} else if (rdtype != dns_rdatatype_key &&
|
|
|
|
rdtype != dns_rdatatype_sig &&
|
|
|
|
rdtype != dns_rdatatype_nsec &&
|
|
|
|
rdtype != dns_rdatatype_rrsig)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
if (header->serial <= serial && !IGNORE(header))
|
|
|
|
{
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
header = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
header = header->down;
|
|
|
|
} while (header != NULL);
|
|
|
|
if (header != NULL) {
|
2025-08-05 18:05:52 +02:00
|
|
|
if (!prio_type(rdtype)) {
|
2025-01-31 09:09:33 +11:00
|
|
|
/*
|
|
|
|
* CNAME is in the priority list, so if
|
|
|
|
* we are done with priority types, we
|
|
|
|
* know there will not be a CNAME, and
|
|
|
|
* are safe to skip the rest.
|
|
|
|
*/
|
|
|
|
return cname;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
other = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cname && other) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
static qpz_changed_t *
|
|
|
|
add_changed(dns_slabheader_t *header, qpz_version_t *version DNS__DB_FLARG) {
|
|
|
|
qpz_changed_t *changed = NULL;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpznode_t *node = HEADERNODE(header);
|
|
|
|
qpzonedb_t *qpdb = node->qpdb;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
changed = isc_mem_get(qpdb->common.mctx, sizeof(*changed));
|
|
|
|
|
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
REQUIRE(version->writer);
|
2023-12-02 01:04:28 -08:00
|
|
|
|
2024-04-29 15:45:26 -07:00
|
|
|
*changed = (qpz_changed_t){ .node = node };
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t
|
|
|
|
recordsize(dns_slabheader_t *header, unsigned int namelen) {
|
2025-02-07 21:21:52 -08:00
|
|
|
return dns_rdataslab_size(header) + sizeof(dns_ttl_t) +
|
|
|
|
sizeof(dns_rdatatype_t) + sizeof(dns_rdataclass_t) + namelen;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-04-29 15:45:26 -07:00
|
|
|
maybe_update_recordsandsize(bool add, qpz_version_t *version,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_t *header, unsigned int namelen) {
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RWLOCK(&version->rwlock, isc_rwlocktype_write);
|
|
|
|
if (add) {
|
2025-02-07 21:21:52 -08:00
|
|
|
version->records += dns_rdataslab_count(header);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
version->xfrsize += recordsize(header, namelen);
|
|
|
|
} else {
|
2025-02-07 21:21:52 -08:00
|
|
|
version->records -= dns_rdataslab_count(header);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
version->xfrsize -= recordsize(header, namelen);
|
|
|
|
}
|
|
|
|
RWUNLOCK(&version->rwlock, isc_rwlocktype_write);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-04-29 15:29:33 -07:00
|
|
|
add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_version_t *version, dns_slabheader_t *newheader, unsigned int options,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool loading, dns_rdataset_t *addedrdataset,
|
2025-02-03 14:06:37 +01:00
|
|
|
isc_stdtime_t now ISC_ATTR_UNUSED DNS__DB_FLARG) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_changed_t *changed = NULL;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
|
|
|
dns_slabtop_t *priotop = NULL;
|
2025-02-07 21:21:52 -08:00
|
|
|
dns_slabheader_t *merged = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result;
|
|
|
|
bool merge = false;
|
2024-05-25 11:46:56 +02:00
|
|
|
uint32_t ntypes;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if ((options & DNS_DBADD_MERGE) != 0) {
|
|
|
|
REQUIRE(version != NULL);
|
|
|
|
merge = true;
|
|
|
|
}
|
|
|
|
|
2024-03-19 17:02:56 +11:00
|
|
|
if (!loading) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* 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, version DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
2024-05-25 11:46:56 +02:00
|
|
|
ntypes = 0;
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
2024-05-25 11:46:56 +02:00
|
|
|
++ntypes;
|
2025-08-05 18:05:52 +02:00
|
|
|
if (prio_type(top->typepair)) {
|
|
|
|
priotop = top;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair == newheader->typepair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If topheader 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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *header = NULL, *header_prev = NULL;
|
|
|
|
if (top != NULL) {
|
|
|
|
header = top->header;
|
|
|
|
while (header != NULL && IGNORE(header)) {
|
|
|
|
header_prev = header;
|
|
|
|
header = header->down;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (header != NULL) {
|
|
|
|
/*
|
|
|
|
* If 'merge' is true and header isn't empty/nonexistent,
|
|
|
|
* we'll try to create a new rdataset that is the union
|
|
|
|
* of 'newheader' and 'header'.
|
|
|
|
*/
|
2025-08-12 11:31:57 +02:00
|
|
|
if (merge && EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
unsigned int flags = 0;
|
|
|
|
INSIST(version->serial >= header->serial);
|
|
|
|
merged = NULL;
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
if ((options & DNS_DBADD_EXACT) != 0) {
|
|
|
|
flags |= DNS_RDATASLAB_EXACT;
|
|
|
|
}
|
|
|
|
if ((options & DNS_DBADD_EXACTTTL) != 0 &&
|
2025-02-03 14:06:37 +01:00
|
|
|
newheader->ttl != header->ttl)
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
result = DNS_R_NOTEXACT;
|
2025-02-03 14:06:37 +01:00
|
|
|
} else if (newheader->ttl != header->ttl) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
flags |= DNS_RDATASLAB_FORCE;
|
|
|
|
}
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = dns_rdataslab_merge(
|
2025-02-07 21:21:52 -08:00
|
|
|
header, newheader, qpdb->common.mctx,
|
|
|
|
qpdb->common.rdclass,
|
2025-08-06 19:34:35 +02:00
|
|
|
DNS_TYPEPAIR_TYPE(header->typepair),
|
|
|
|
flags, qpdb->maxrrperset, &merged);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
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);
|
2025-02-07 21:21:52 -08:00
|
|
|
newheader = merged;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_reset(newheader,
|
|
|
|
(dns_dbnode_t *)node);
|
|
|
|
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 {
|
2024-08-29 16:24:48 +09:00
|
|
|
if (result == DNS_R_TOOMANYRECORDS) {
|
|
|
|
dns__db_logtoomanyrecords(
|
|
|
|
(dns_db_t *)qpdb, nodename,
|
2025-08-06 19:34:35 +02:00
|
|
|
DNS_TYPEPAIR_TYPE(
|
|
|
|
header->typepair),
|
2024-08-29 16:24:48 +09:00
|
|
|
"updating", qpdb->maxrrperset);
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_destroy(&newheader);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
INSIST(version->serial >= top->header->serial);
|
|
|
|
INSIST(top->typepair == newheader->typepair);
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (loading) {
|
|
|
|
newheader->down = NULL;
|
|
|
|
if (RESIGN(newheader)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(newheader);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/* resigndelete not needed here */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There are no other references to 'header' when
|
|
|
|
* loading, so we MAY clean up 'header' now.
|
|
|
|
* Since we don't generate changed records when
|
|
|
|
* loading, we MUST clean up 'header' now.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
newheader->top = top;
|
|
|
|
top->header = newheader;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
maybe_update_recordsandsize(false, version, header,
|
|
|
|
nodename->length);
|
2025-08-05 18:05:52 +02:00
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_destroy(&header);
|
|
|
|
} else {
|
|
|
|
if (RESIGN(newheader)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(newheader);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
resigndelete(qpdb, version,
|
|
|
|
header DNS__DB_FLARG_PASS);
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
|
|
|
|
if (header_prev != NULL) {
|
|
|
|
header_prev->down = newheader;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else {
|
2025-08-05 18:05:52 +02:00
|
|
|
top->header = newheader;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
|
|
|
|
newheader->top = top;
|
|
|
|
newheader->down = header;
|
|
|
|
|
2024-05-14 12:36:58 -07:00
|
|
|
node->dirty = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (changed != NULL) {
|
|
|
|
changed->dirty = true;
|
|
|
|
}
|
|
|
|
maybe_update_recordsandsize(false, version, header,
|
|
|
|
nodename->length);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No non-IGNORED rdatasets of the given type exist at
|
|
|
|
* this node.
|
|
|
|
*
|
|
|
|
* If we're trying to delete the type, don't bother.
|
|
|
|
*/
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(newheader)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_destroy(&newheader);
|
|
|
|
return DNS_R_UNCHANGED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RESIGN(newheader)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(newheader);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
resigndelete(qpdb, version, header DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top != NULL) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* We have a list of rdatasets of the given type,
|
|
|
|
* but they're all marked IGNORE. We simply insert
|
|
|
|
* the new rdataset at the head of the list.
|
|
|
|
*
|
|
|
|
* Ignored rdatasets cannot occur during loading, so
|
|
|
|
* we INSIST on it.
|
|
|
|
*/
|
|
|
|
INSIST(!loading);
|
2025-08-05 18:05:52 +02:00
|
|
|
INSIST(version->serial >= top->header->serial);
|
|
|
|
newheader->top = top;
|
|
|
|
newheader->down = top->header;
|
|
|
|
top->header = newheader;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (changed != NULL) {
|
|
|
|
changed->dirty = true;
|
|
|
|
}
|
2024-05-14 12:36:58 -07:00
|
|
|
node->dirty = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No rdatasets of the given type exist at the node.
|
|
|
|
*/
|
2024-05-25 11:46:56 +02:00
|
|
|
|
|
|
|
if (qpdb->maxtypepername > 0 &&
|
|
|
|
ntypes >= qpdb->maxtypepername)
|
|
|
|
{
|
|
|
|
dns_slabheader_destroy(&newheader);
|
|
|
|
return DNS_R_TOOMANYRECORDS;
|
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *newtop = dns_slabtop_new(
|
|
|
|
((dns_db_t *)qpdb)->mctx, newheader->typepair);
|
|
|
|
|
|
|
|
newheader->top = newtop;
|
|
|
|
newtop->header = newheader;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-08-06 19:34:35 +02:00
|
|
|
if (prio_type(newheader->typepair)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/* This is a priority type, prepend it */
|
2025-08-05 18:05:52 +02:00
|
|
|
newtop->next = node->data;
|
|
|
|
node->data = newtop;
|
|
|
|
} else if (priotop != NULL) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/* Append after the priority headers */
|
2025-08-05 18:05:52 +02:00
|
|
|
newtop->next = priotop->next;
|
|
|
|
priotop->next = newtop;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else {
|
|
|
|
/* There were no priority headers */
|
2025-08-05 18:05:52 +02:00
|
|
|
newtop->next = node->data;
|
|
|
|
node->data = newtop;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
maybe_update_recordsandsize(true, version, newheader, nodename->length);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the node now contains CNAME and other data.
|
|
|
|
*/
|
2024-03-19 17:02:56 +11:00
|
|
|
if (cname_and_other(node, version->serial)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return DNS_R_CNAMEANDOTHER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addedrdataset != NULL) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(qpdb, node, newheader,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
addedrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
wildcardmagic(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
|
2025-05-26 17:36:33 +02:00
|
|
|
dns_namespace_t nspace) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result;
|
|
|
|
dns_name_t foundname;
|
|
|
|
unsigned int n;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&foundname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
n = dns_name_countlabels(name);
|
|
|
|
INSIST(n >= 2);
|
|
|
|
n--;
|
|
|
|
dns_name_getlabelsequence(name, 1, n, &foundname);
|
|
|
|
|
|
|
|
/* insert an empty node, if needed, to hold the wildcard bit */
|
2025-05-26 17:36:33 +02:00
|
|
|
result = dns_qp_getname(qp, &foundname, nspace, (void **)&node, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
INSIST(node == NULL);
|
2025-07-07 11:42:17 +02:00
|
|
|
node = new_qpznode(qpdb, &foundname, nspace);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
result = dns_qp_insert(qp, node, 0);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_unref(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2024-05-14 12:36:58 -07:00
|
|
|
node->wild = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
|
2025-05-26 17:36:33 +02:00
|
|
|
dns_namespace_t nspace) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_name_t foundname;
|
|
|
|
unsigned int n, l, i;
|
|
|
|
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&foundname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
n = dns_name_countlabels(name);
|
|
|
|
l = dns_name_countlabels(&qpdb->common.origin);
|
|
|
|
i = l + 1;
|
|
|
|
while (i < n) {
|
|
|
|
dns_name_getlabelsequence(name, n - i, i, &foundname);
|
|
|
|
if (dns_name_iswildcard(&foundname)) {
|
2025-05-26 17:36:33 +02:00
|
|
|
wildcardmagic(qpdb, qp, &foundname, nspace);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
loading_addrdataset(void *arg, const dns_name_t *name,
|
|
|
|
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_load_t *loadctx = arg;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
isc_region_t region;
|
|
|
|
dns_slabheader_t *newheader = NULL;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2025-07-07 11:29:45 +02:00
|
|
|
addwildcards(qpdb, loadctx->tree, name, DNS_DBNAMESPACE_NORMAL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dns_name_iswildcard(name)) {
|
|
|
|
if (rdataset->type == dns_rdatatype_ns) {
|
|
|
|
/*
|
|
|
|
* NS owners cannot legally be wild cards.
|
|
|
|
*/
|
2024-02-05 16:11:16 -08:00
|
|
|
return DNS_R_INVALIDNS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rdataset->type == dns_rdatatype_nsec3) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* NSEC3 owners cannot legally be wild cards.
|
|
|
|
*/
|
2024-02-05 16:11:16 -08:00
|
|
|
return DNS_R_INVALIDNSEC3;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2024-02-05 16:11:16 -08:00
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
wildcardmagic(qpdb, loadctx->tree, name,
|
|
|
|
DNS_DBNAMESPACE_NORMAL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2024-02-05 16:11:16 -08:00
|
|
|
loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion,
|
|
|
|
qpdb->maxrrperset);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-29 16:24:48 +09:00
|
|
|
if (result == DNS_R_TOOMANYRECORDS) {
|
|
|
|
dns__db_logtoomanyrecords((dns_db_t *)qpdb, name,
|
|
|
|
rdataset->type, "adding",
|
|
|
|
qpdb->maxrrperset);
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
newheader = (dns_slabheader_t *)region.base;
|
2025-07-15 12:16:39 +02:00
|
|
|
dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
|
2025-02-07 21:06:34 -08:00
|
|
|
|
|
|
|
newheader->ttl = rdataset->ttl;
|
|
|
|
newheader->trust = rdataset->trust;
|
|
|
|
newheader->serial = 1;
|
|
|
|
newheader->count = 1;
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_setownercase(newheader, name);
|
|
|
|
|
2025-07-09 16:56:22 +02:00
|
|
|
if (rdataset->attributes.resign) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
|
|
|
|
newheader->resign =
|
|
|
|
(isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
|
|
|
|
1);
|
|
|
|
newheader->resign_lsb = rdataset->resign & 0x1;
|
|
|
|
}
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
result = add(qpdb, node, name, qpdb->current_version, newheader,
|
|
|
|
DNS_DBADD_MERGE, true, NULL, 0 DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
delegating_type(qpdb, node, rdataset->type))
|
|
|
|
{
|
2024-05-14 12:36:58 -07:00
|
|
|
node->delegating = true;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else if (result == DNS_R_UNCHANGED) {
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-05 16:11:16 -08:00
|
|
|
static void
|
|
|
|
loading_setup(void *arg) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_load_t *loadctx = arg;
|
2024-02-05 16:11:16 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
|
|
|
|
|
|
|
|
dns_qpmulti_write(qpdb->tree, &loadctx->tree);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
loading_commit(void *arg) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_load_t *loadctx = arg;
|
2024-02-05 16:11:16 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
|
|
|
|
|
|
|
|
if (loadctx->tree != NULL) {
|
|
|
|
dns_qp_compact(loadctx->tree, DNS_QPGC_MAYBE);
|
|
|
|
dns_qpmulti_commit(qpdb->tree, &loadctx->tree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static isc_result_t
|
|
|
|
beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_load_t *loadctx = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
|
|
|
loadctx = isc_mem_get(qpdb->common.mctx, sizeof(*loadctx));
|
2024-04-29 15:45:26 -07:00
|
|
|
*loadctx = (qpz_load_t){ .db = db };
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
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;
|
2024-02-05 16:11:16 -08:00
|
|
|
callbacks->setup = loading_setup;
|
|
|
|
callbacks->commit = loading_commit;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
callbacks->add_private = loadctx;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static isc_result_t
|
|
|
|
endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_load_t *loadctx = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
|
|
|
loadctx = callbacks->add_private;
|
|
|
|
REQUIRE(loadctx != NULL);
|
|
|
|
REQUIRE(loadctx->db == db);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_write);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
REQUIRE((qpdb->attributes & QPDB_ATTR_LOADING) != 0);
|
|
|
|
REQUIRE((qpdb->attributes & QPDB_ATTR_LOADED) == 0);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
qpdb->attributes &= ~QPDB_ATTR_LOADING;
|
|
|
|
qpdb->attributes |= QPDB_ATTR_LOADED;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
if (qpdb->origin != NULL) {
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = qpdb->current_version;
|
2023-11-19 00:00:49 -08:00
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
2024-11-05 16:13:10 +01:00
|
|
|
setsecure(db, version, (dns_dbnode_t *)qpdb->origin);
|
2023-11-19 00:00:49 -08:00
|
|
|
} else {
|
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
callbacks->add = NULL;
|
2024-02-05 16:11:16 -08:00
|
|
|
callbacks->setup = NULL;
|
|
|
|
callbacks->commit = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
callbacks->add_private = NULL;
|
|
|
|
|
|
|
|
isc_mem_put(qpdb->common.mctx, loadctx, sizeof(*loadctx));
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static bool
|
|
|
|
issecure(dns_db_t *db) {
|
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
bool secure;
|
|
|
|
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(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 *dbversion, dns_hash_t *hash,
|
|
|
|
uint8_t *flags, uint16_t *iterations, unsigned char *salt,
|
|
|
|
size_t *salt_length) {
|
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
isc_result_t result = ISC_R_NOTFOUND;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
INSIST(version == NULL || version->qpdb == qpdb);
|
|
|
|
|
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_read);
|
|
|
|
if (version == NULL) {
|
|
|
|
version = qpdb->current_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version->havensec3) {
|
|
|
|
if (hash != NULL) {
|
|
|
|
*hash = version->hash;
|
|
|
|
}
|
|
|
|
if (salt != NULL && salt_length != NULL) {
|
|
|
|
REQUIRE(*salt_length >= version->salt_length);
|
|
|
|
memmove(salt, version->salt, version->salt_length);
|
|
|
|
}
|
|
|
|
if (salt_length != NULL) {
|
|
|
|
*salt_length = version->salt_length;
|
|
|
|
}
|
|
|
|
if (iterations != NULL) {
|
|
|
|
*iterations = version->iterations;
|
|
|
|
}
|
|
|
|
if (flags != NULL) {
|
|
|
|
*flags = version->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 *dbversion, uint64_t *records,
|
|
|
|
uint64_t *xfrsize) {
|
|
|
|
qpzonedb_t *qpdb = NULL;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
INSIST(version == NULL || version->qpdb == qpdb);
|
|
|
|
|
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_read);
|
|
|
|
if (version == NULL) {
|
|
|
|
version = qpdb->current_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
RWLOCK(&version->rwlock, isc_rwlocktype_read);
|
|
|
|
SET_IF_NOT_NULL(records, version->records);
|
|
|
|
|
|
|
|
SET_IF_NOT_NULL(xfrsize, version->xfrsize);
|
|
|
|
RWUNLOCK(&version->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) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
dns_slabheader_t *header = NULL, oldheader;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
REQUIRE(rdataset->methods == &dns_rdataslab_rdatasetmethods);
|
|
|
|
|
2025-02-08 15:41:31 -08:00
|
|
|
header = dns_rdataset_getheader(rdataset);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(HEADERNODE(header));
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
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));
|
2025-07-08 16:29:56 +02:00
|
|
|
LOCK(get_heap_lock(header));
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
if (resign == 0) {
|
2025-07-08 16:29:56 +02:00
|
|
|
isc_heap_delete(HEADERNODE(header)->heap->heap,
|
|
|
|
header->heap_index);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
header->heap_index = 0;
|
|
|
|
} else if (resign_sooner(header, &oldheader)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
isc_heap_increased(HEADERNODE(header)->heap->heap,
|
|
|
|
header->heap_index);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
} else if (resign_sooner(&oldheader, header)) {
|
2025-07-08 16:29:56 +02:00
|
|
|
isc_heap_decreased(HEADERNODE(header)->heap->heap,
|
|
|
|
header->heap_index);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
2025-07-08 16:29:56 +02:00
|
|
|
UNLOCK(get_heap_lock(header));
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
} else if (resign != 0) {
|
|
|
|
DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_RESIGN);
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(header);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-03-25 17:23:19 -07:00
|
|
|
getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *foundname,
|
|
|
|
dns_typepair_t *typepair) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-03-13 15:59:53 -07:00
|
|
|
dns_slabheader_t *header = NULL;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2024-03-25 17:23:19 -07:00
|
|
|
isc_result_t result = ISC_R_NOTFOUND;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2024-03-25 17:23:19 -07:00
|
|
|
REQUIRE(resign != NULL);
|
|
|
|
REQUIRE(foundname != NULL);
|
|
|
|
REQUIRE(typepair != NULL);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
LOCK(&qpdb->heap->lock);
|
|
|
|
header = isc_heap_element(qpdb->heap->heap, 1);
|
2024-03-13 15:59:53 -07:00
|
|
|
if (header == NULL) {
|
2025-07-08 16:29:56 +02:00
|
|
|
UNLOCK(&qpdb->heap->lock);
|
2024-03-13 15:59:53 -07:00
|
|
|
return ISC_R_NOTFOUND;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(HEADERNODE(header));
|
2025-07-08 16:29:56 +02:00
|
|
|
UNLOCK(&qpdb->heap->lock);
|
2024-03-25 17:23:19 -07:00
|
|
|
|
|
|
|
again:
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2024-03-25 17:23:19 -07:00
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
LOCK(&qpdb->heap->lock);
|
|
|
|
header = isc_heap_element(qpdb->heap->heap, 1);
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
if (header != NULL && qpzone_get_lock(HEADERNODE(header)) != nlock) {
|
2025-07-08 16:29:56 +02:00
|
|
|
UNLOCK(&qpdb->heap->lock);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2025-07-08 15:52:35 +02:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(HEADERNODE(header));
|
2024-03-25 17:23:19 -07:00
|
|
|
goto again;
|
|
|
|
}
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-03-25 17:23:19 -07:00
|
|
|
if (header != NULL) {
|
|
|
|
*resign = RESIGN(header)
|
|
|
|
? (header->resign << 1) | header->resign_lsb
|
|
|
|
: 0;
|
2024-03-13 15:59:53 -07:00
|
|
|
dns_name_copy(&HEADERNODE(header)->name, foundname);
|
2025-08-06 19:34:35 +02:00
|
|
|
*typepair = header->typepair;
|
2024-03-25 17:23:19 -07:00
|
|
|
result = ISC_R_SUCCESS;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
2025-07-08 16:29:56 +02:00
|
|
|
UNLOCK(&qpdb->heap->lock);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-03-25 17:23:19 -07:00
|
|
|
return result;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static isc_result_t
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(!IS_STUB(qpdb));
|
|
|
|
REQUIRE(stats != NULL);
|
|
|
|
|
|
|
|
isc_stats_attach(stats, &qpdb->gluecachestats);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
|
|
|
|
bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
2025-07-07 11:29:45 +02:00
|
|
|
dns_namespace_t nspace = nsec3 ? DNS_DBNAMESPACE_NSEC3
|
|
|
|
: DNS_DBNAMESPACE_NORMAL;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
dns_qpread_t qpr = { 0 };
|
|
|
|
dns_qp_t *qp = NULL;
|
|
|
|
|
|
|
|
if (create) {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_write(qpdb->tree, &qp);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
} else {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_query(qpdb->tree, &qpr);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
qp = (dns_qp_t *)&qpr;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-05-26 17:36:33 +02:00
|
|
|
result = dns_qp_getname(qp, name, nspace, (void **)&node, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
if (!create) {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpread_destroy(qpdb->tree, &qpr);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-07-07 11:42:17 +02:00
|
|
|
node = new_qpznode(qpdb, name, nspace);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
result = dns_qp_insert(qp, node, 0);
|
2025-02-11 16:08:29 -08:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_unref(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
if (!nsec3) {
|
2025-05-26 17:36:33 +02:00
|
|
|
addwildcards(qpdb, qp, name, nspace);
|
2025-02-11 16:08:29 -08:00
|
|
|
if (dns_name_iswildcard(name)) {
|
2025-05-26 17:36:33 +02:00
|
|
|
wildcardmagic(qpdb, qp, name, nspace);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(node->nspace == DNS_DBNAMESPACE_NSEC3 || !nsec3);
|
2025-02-11 16:08:29 -08:00
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
if (create) {
|
|
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_commit(qpdb->tree, &qp);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
} else {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpread_destroy(qpdb->tree, &qpr);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
|
|
|
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
return findnodeintree(qpdb, name, create, false,
|
|
|
|
nodep DNS__DB_FLARG_PASS);
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
|
|
|
|
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
return findnodeintree(qpdb, name, create, true,
|
|
|
|
nodep DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2024-04-29 15:45:26 -07:00
|
|
|
matchparams(dns_slabheader_t *header, qpz_search_t *search) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_rdata_nsec3_t nsec3;
|
|
|
|
unsigned char *raw = NULL;
|
|
|
|
unsigned int rdlen, count;
|
|
|
|
isc_region_t region;
|
|
|
|
isc_result_t result;
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
REQUIRE(header->typepair == DNS_TYPEPAIR(dns_rdatatype_nsec3));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
raw = (unsigned char *)header + sizeof(*header);
|
2025-08-17 13:59:05 -07:00
|
|
|
count = get_uint16(raw);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
while (count-- > 0) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
|
2025-08-17 13:59:05 -07:00
|
|
|
rdlen = get_uint16(raw);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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->version->hash &&
|
|
|
|
nsec3.iterations == search->version->iterations &&
|
|
|
|
nsec3.salt_length == search->version->salt_length &&
|
|
|
|
memcmp(nsec3.salt, search->version->salt,
|
|
|
|
nsec3.salt_length) == 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
|
|
|
|
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_name_t *zcname = NULL;
|
2025-08-06 19:34:35 +02:00
|
|
|
dns_typepair_t typepair;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
REQUIRE(search != NULL);
|
|
|
|
REQUIRE(search->zonecut != NULL);
|
|
|
|
REQUIRE(search->zonecut_header != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The caller MUST NOT be holding any node locks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
node = search->zonecut;
|
2025-08-06 19:34:35 +02:00
|
|
|
typepair = search->zonecut_header->typepair;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
search->need_cleanup = false;
|
|
|
|
}
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bindrdataset(search->qpdb, node, search->zonecut_header,
|
2025-02-03 14:06:37 +01:00
|
|
|
rdataset DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (sigrdataset != NULL && search->zonecut_sigheader != NULL) {
|
|
|
|
bindrdataset(search->qpdb, node,
|
2025-02-03 14:06:37 +01:00
|
|
|
search->zonecut_sigheader,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
sigrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (typepair == DNS_TYPEPAIR(dns_rdatatype_dname)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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
|
2024-04-29 15:45:26 -07:00
|
|
|
step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_name_t *nextname) {
|
|
|
|
dns_fixedname_t fnodename;
|
|
|
|
dns_name_t *nodename = dns_fixedname_initname(&fnodename);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
result = dns_qpiter_current(it, nodename, (void **)&node, NULL);
|
|
|
|
while (result == ISC_R_SUCCESS) {
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
|
|
|
dns_slabheader_t *found = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
while (header != NULL &&
|
|
|
|
(IGNORE(header) ||
|
|
|
|
header->serial > search->serial))
|
|
|
|
{
|
|
|
|
header = header->down;
|
2025-02-14 21:42:34 -08:00
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
if (header != NULL && EXISTS(header)) {
|
|
|
|
found = header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2025-08-05 18:05:52 +02:00
|
|
|
if (found != NULL) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction == FORWARD) {
|
|
|
|
result = dns_qpiter_next(it, nodename, (void **)&node,
|
|
|
|
NULL);
|
|
|
|
} else {
|
|
|
|
result = dns_qpiter_prev(it, nodename, (void **)&node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (nextname != NULL) {
|
|
|
|
dns_name_copy(nodename, nextname);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2024-04-29 15:45:26 -07:00
|
|
|
activeempty(qpz_search_t *search, dns_qpiter_t *it, const dns_name_t *current) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_fixedname_t fnext;
|
|
|
|
dns_name_t *next = dns_fixedname_initname(&fnext);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The iterator is currently pointed at the predecessor
|
|
|
|
* of the name we were searching for. Step the iterator
|
|
|
|
* forward, then step() will continue forward until it
|
|
|
|
* finds a node with active data. If that node is a
|
|
|
|
* subdomain of the one we were looking for, then we're
|
|
|
|
* at an active empty nonterminal node.
|
|
|
|
*/
|
Fix Coverity CID 487882: Error handling issues
The dns_qpiter_next() was called without checking the return value. If
we cannot move the iterator forward, there is no use in calling the
step() function.
/lib/dns/qpzone.c: 2804 in activeempty()
2798 * of the name we were searching for. Step the iterator
2799 * forward, then step() will continue forward until it
2800 * finds a node with active data. If that node is a
2801 * subdomain of the one we were looking for, then we're
2802 * at an active empty nonterminal node.
2803 */
>>> CID 487882: Error handling issues (CHECKED_RETURN)
>>> Calling "dns_qpiter_next" without checking return value (as is done elsewhere 26 out of 27 times).
2804 dns_qpiter_next(it, NULL, NULL, NULL);
2805 return (step(search, it, FORWARD, next) &&
2806 dns_name_issubdomain(next, current));
2807 }
2024-03-12 11:59:38 +01:00
|
|
|
isc_result_t result = dns_qpiter_next(it, NULL, NULL, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/* An ENT at the end of the zone is impossible */
|
|
|
|
return false;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return step(search, it, FORWARD, next) &&
|
|
|
|
dns_name_issubdomain(next, current);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2024-04-29 15:45:26 -07:00
|
|
|
wildcard_blocked(qpz_search_t *search, const dns_name_t *qname,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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 it;
|
|
|
|
bool check_next = false;
|
|
|
|
bool check_prev = false;
|
|
|
|
unsigned int n;
|
|
|
|
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&name);
|
|
|
|
dns_name_init(&tname);
|
|
|
|
dns_name_init(&rname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
it = search->iter;
|
|
|
|
check_prev = step(search, &it, BACK, prev);
|
|
|
|
|
|
|
|
/* Now reset the iterator and look for a successor with data. */
|
|
|
|
it = search->iter;
|
|
|
|
result = dns_qpiter_next(&it, NULL, NULL, NULL);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
check_next = step(search, &it, 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
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname,
|
2025-05-26 17:36:33 +02:00
|
|
|
dns_namespace_t nspace) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
|
|
|
dns_slabheader_t *found = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result = ISC_R_NOTFOUND;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
|
|
|
bool wild, active;
|
|
|
|
|
|
|
|
dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL);
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (header->serial <= search->serial &&
|
2025-08-12 11:31:57 +02:00
|
|
|
!IGNORE(header) && EXISTS(header))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
2025-08-05 18:05:52 +02:00
|
|
|
found = header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
active = (found != NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
wild = node->wild;
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if (wild) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *wnode = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_fixedname_t fwname;
|
|
|
|
dns_name_t *wname = dns_fixedname_initname(&fwname);
|
|
|
|
dns_qpiter_t wit;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct the wildcard name for this level.
|
|
|
|
*/
|
|
|
|
result = dns_name_concatenate(dns_wildcardname,
|
2025-02-21 00:56:47 -08:00
|
|
|
&node->name, wname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(&search->qpr, wname, nspace,
|
|
|
|
NULL, &wit, NULL,
|
|
|
|
(void **)&wnode, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We have found the wildcard node. If it
|
|
|
|
* is active in the search's version, we're
|
|
|
|
* done.
|
|
|
|
*/
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(wnode);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = wnode->data; top != NULL;
|
|
|
|
top = top->next)
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *header = top->header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (header->serial <= search->serial &&
|
2025-08-12 11:31:57 +02:00
|
|
|
!IGNORE(header) && EXISTS(header))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
2025-08-05 18:05:52 +02:00
|
|
|
found = header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2025-08-05 18:05:52 +02:00
|
|
|
if (found != NULL ||
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
activeempty(search, &wit, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find node of the NSEC/NSEC3 record that is 'name'.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2024-04-29 15:45:26 -07:00
|
|
|
previous_closest_nsec(dns_rdatatype_t type, qpz_search_t *search,
|
2024-04-29 15:29:33 -07:00
|
|
|
dns_name_t *name, qpznode_t **nodep, dns_qpiter_t *nit,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool *firstp) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_qpread_t qpr;
|
|
|
|
|
|
|
|
REQUIRE(nodep != NULL && *nodep == NULL);
|
|
|
|
REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL);
|
|
|
|
|
|
|
|
if (type == dns_rdatatype_nsec3) {
|
|
|
|
result = dns_qpiter_prev(&search->iter, name, (void **)nodep,
|
|
|
|
NULL);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_query(search->qpdb->tree, &qpr);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (*firstp) {
|
|
|
|
/*
|
|
|
|
* Construct the name of the second node to check.
|
|
|
|
* It is the first node sought in the NSEC tree.
|
|
|
|
*/
|
|
|
|
*firstp = false;
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NSEC,
|
2025-05-27 10:57:11 +02:00
|
|
|
NULL, nit, NULL, NULL, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
INSIST(result != ISC_R_NOTFOUND);
|
|
|
|
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(nit, name, NULL, NULL);
|
|
|
|
} else if (result == DNS_R_PARTIALMATCH) {
|
|
|
|
/*
|
|
|
|
* The iterator is already where we want it.
|
|
|
|
*/
|
|
|
|
dns_qpiter_current(nit, name, NULL, NULL);
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
} 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(nit, name, NULL, NULL);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*nodep = NULL;
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_lookup(
|
|
|
|
&search->qpr, name, DNS_DBNAMESPACE_NORMAL, NULL,
|
|
|
|
&search->iter, &search->chain, (void **)nodep, NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_DATABASE,
|
2023-11-19 00:00:49 -08:00
|
|
|
DNS_LOGMODULE_DB, ISC_LOG_ERROR,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
"previous_closest_nsec(): %s",
|
|
|
|
isc_result_totext(result));
|
|
|
|
result = DNS_R_BADDB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpread_destroy(search->qpdb->tree, &qpr);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2024-04-29 15:45:26 -07:00
|
|
|
find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset, bool nsec3,
|
|
|
|
bool secure DNS__DB_FLARG) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL, *prevnode = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_qpiter_t nseciter;
|
|
|
|
bool empty_node;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_fixedname_t fname;
|
|
|
|
dns_name_t *name = dns_fixedname_initname(&fname);
|
2025-08-06 19:34:35 +02:00
|
|
|
dns_rdatatype_t matchtype = nsec3 ? dns_rdatatype_nsec3
|
|
|
|
: dns_rdatatype_nsec;
|
Remove the negative type logic from qpcache
Previously, when a negative header was stored in the cache, it would be
stored in the dns_typepair_t as .type = 0, .covers = <negative type>.
When searching the cache internally, we would have to look for both
positive and negative typepair and the slabheader .down list could be a
mix of positive and negative types.
Remove the extra representation of the negative type and simply use the
negative attribute on the slabheader. Other units (namely dns_ncache)
can still insert the (0, type) negative rdatasets into the cache, but
internally, those will be converted into (type, 0) slabheaders, and vice
versa - when binding the rdatasets, the negative (type, 0) slabheader
will be converted to (0, type) rdataset. Simple DNS_TYPEPAIR() helper
macro was added to simplify converting single rdatatype to typepair
value.
As a side-effect, the search logic in all places can exit early if
there's a negative header for the type we are looking for, f.e. when
searching for the zone cut, we don't have to walk through all the
slabheaders, if there's a stored negative slabheader.
2025-08-11 09:39:13 +02:00
|
|
|
dns_typepair_t typepair = DNS_TYPEPAIR(matchtype);
|
2025-08-12 07:47:03 +02:00
|
|
|
dns_typepair_t sigpair = DNS_SIGTYPEPAIR(matchtype);
|
2025-08-06 19:34:35 +02:00
|
|
|
bool wraps = nsec3;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool first = true;
|
|
|
|
bool need_sig = secure;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the auxiliary tree only starting with the second node in the
|
|
|
|
* hope that the original node will be right much of the time.
|
|
|
|
*/
|
|
|
|
result = dns_qpiter_current(&search->iter, name, (void **)&node, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
again:
|
|
|
|
do {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_t *found = NULL, *foundsig = NULL;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
empty_node = true;
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* Look for an active, extant NSEC or RRSIG NSEC.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if (header->serial <= search->serial &&
|
|
|
|
!IGNORE(header))
|
|
|
|
{
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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;
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair == typepair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
found = header;
|
|
|
|
if (foundsig != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair == sigpair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
foundsig = header;
|
|
|
|
if (found != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!empty_node) {
|
|
|
|
if (found != NULL && search->version->havensec3 &&
|
2025-08-05 18:05:52 +02:00
|
|
|
found->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_nsec3) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
!matchparams(found, search))
|
|
|
|
{
|
|
|
|
empty_node = true;
|
|
|
|
found = NULL;
|
|
|
|
foundsig = NULL;
|
2025-08-06 19:34:35 +02:00
|
|
|
result = previous_closest_nsec(typepair, search,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
name, &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.
|
|
|
|
*/
|
|
|
|
dns_name_copy(name, foundname);
|
|
|
|
if (nodep != NULL) {
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(
|
|
|
|
search->qpdb,
|
|
|
|
node DNS__DB_FLARG_PASS);
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
bindrdataset(search->qpdb, node, found,
|
|
|
|
rdataset DNS__DB_FLARG_PASS);
|
|
|
|
if (foundsig != NULL) {
|
|
|
|
bindrdataset(
|
|
|
|
search->qpdb, node, foundsig,
|
|
|
|
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(
|
2025-08-06 19:34:35 +02:00
|
|
|
typepair, search, name, &prevnode,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
&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.
|
|
|
|
*/
|
2025-08-06 19:34:35 +02:00
|
|
|
result = previous_closest_nsec(typepair, search, name,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
&prevnode, &nseciter,
|
|
|
|
&first);
|
|
|
|
}
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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) {
|
|
|
|
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
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_search_t *search = arg;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for an NS or DNAME rdataset active in our version.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
|
|
|
|
top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
|
|
|
|
top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
do {
|
|
|
|
if (header->serial <= search->serial &&
|
|
|
|
!IGNORE(header))
|
|
|
|
{
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
header = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
header = header->down;
|
|
|
|
}
|
|
|
|
} while (header != NULL);
|
|
|
|
if (header != NULL) {
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_dname))
|
|
|
|
{
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dname_header = header;
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair ==
|
2025-08-12 07:47:03 +02:00
|
|
|
DNS_SIGTYPEPAIR(dns_rdatatype_dname))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
sigdname_header = header;
|
|
|
|
} else if (node != search->qpdb->origin ||
|
|
|
|
IS_STUB(search->qpdb))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We've found an NS rdataset that
|
|
|
|
* isn't at the origin node.
|
|
|
|
*/
|
|
|
|
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.
|
|
|
|
*/
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(search->qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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);
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&node->name, zcname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-01-30 12:33:48 +01:00
|
|
|
static void
|
|
|
|
qpz_search_init(qpz_search_t *search, qpzonedb_t *db, qpz_version_t *version,
|
|
|
|
unsigned int options) {
|
|
|
|
/*
|
|
|
|
* qpz_search_t contains two structures with large buffers (dns_qpiter_t
|
|
|
|
* and dns_qpchain_t). Those two structures will be initialized later by
|
|
|
|
* dns_qp_lookup anyway.
|
|
|
|
* To avoid the overhead of zero initialization, we avoid designated
|
|
|
|
* initializers and initialize all "small" fields manually.
|
|
|
|
*/
|
|
|
|
search->qpdb = db;
|
|
|
|
search->version = version;
|
|
|
|
search->qpr = (dns_qpread_t){};
|
|
|
|
search->serial = version->serial;
|
|
|
|
search->options = options;
|
|
|
|
/*
|
|
|
|
* qpch->in -- init in dns_qp_lookup
|
|
|
|
* qpiter -- init in dns_qp_lookup
|
|
|
|
*/
|
|
|
|
search->copy_name = false;
|
|
|
|
search->need_cleanup = false;
|
|
|
|
search->wild = false;
|
|
|
|
search->zonecut = NULL;
|
|
|
|
search->zonecut_header = NULL;
|
|
|
|
search->zonecut_sigheader = NULL;
|
|
|
|
dns_fixedname_init(&search->zonecut_name);
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_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) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t result;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool cname_ok = true, close_version = false;
|
|
|
|
bool maybe_zonecut = false, at_zonecut = false;
|
|
|
|
bool wild = false, empty_node = false;
|
|
|
|
bool nsec3 = false;
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_t *found = NULL, *nsecheader = NULL;
|
|
|
|
dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL;
|
2025-08-06 19:34:35 +02:00
|
|
|
dns_typepair_t sigpair;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
bool active;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE((qpzonedb_t *)db));
|
|
|
|
INSIST(version == NULL ||
|
2024-04-29 15:45:26 -07:00
|
|
|
((qpz_version_t *)version)->qpdb == (qpzonedb_t *)db);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the caller didn't supply a version, attach to the current
|
|
|
|
* version.
|
|
|
|
*/
|
|
|
|
if (version == NULL) {
|
|
|
|
currentversion(db, &version);
|
|
|
|
close_version = true;
|
|
|
|
}
|
|
|
|
|
2025-05-26 17:36:33 +02:00
|
|
|
dns_namespace_t nspace;
|
2025-01-30 12:33:48 +01:00
|
|
|
qpz_search_t search;
|
|
|
|
qpz_search_init(&search, (qpzonedb_t *)db, (qpz_version_t *)version,
|
|
|
|
options);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
if ((options & DNS_DBFIND_FORCENSEC3) != 0) {
|
|
|
|
nsec3 = true;
|
2025-07-07 11:29:45 +02:00
|
|
|
nspace = DNS_DBNAMESPACE_NSEC3;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else {
|
2025-07-07 11:29:45 +02:00
|
|
|
nspace = DNS_DBNAMESPACE_NORMAL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_query(qpdb->tree, &search.qpr);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Search down from the root of the tree.
|
|
|
|
*/
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(&search.qpr, name, nspace, NULL, &search.iter,
|
|
|
|
&search.chain, (void **)&node, NULL);
|
2024-04-10 23:48:24 -04:00
|
|
|
if (result != ISC_R_NOTFOUND) {
|
|
|
|
dns_name_copy(&node->name, foundname);
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 clen = dns_qpchain_length(&search.chain);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
clen--;
|
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < clen && search.zonecut == NULL; i++) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *n = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_result_t tresult;
|
|
|
|
|
|
|
|
dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL);
|
2024-11-14 11:18:00 +01:00
|
|
|
tresult = qpzone_check_zonecut(n, &search DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
if (tresult != DNS_R_CONTINUE) {
|
|
|
|
result = tresult;
|
|
|
|
search.chain.len = i - 1;
|
2024-12-19 14:19:43 -08:00
|
|
|
dns_name_copy(&n->name, foundname);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
node = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == DNS_R_PARTIALMATCH) {
|
|
|
|
partial_match:
|
|
|
|
if (search.zonecut != NULL) {
|
2024-11-14 11:18:00 +01:00
|
|
|
result = qpzone_setup_delegation(
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
&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.
|
|
|
|
*/
|
2025-05-26 17:36:33 +02:00
|
|
|
result = find_wildcard(&search, &node, name, nspace);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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 (!nsec3) {
|
|
|
|
/*
|
|
|
|
* 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.version->secure && !search.version->havensec3) ||
|
|
|
|
nsec3)
|
|
|
|
{
|
|
|
|
result = find_closest_nsec(
|
|
|
|
&search, nodep, foundname, rdataset,
|
|
|
|
sigrdataset, nsec3,
|
|
|
|
search.version->secure DNS__DB_FLARG_PASS);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = active ? DNS_R_EMPTYNAME
|
|
|
|
: DNS_R_NXDOMAIN;
|
|
|
|
}
|
|
|
|
} else {
|
2024-10-10 06:59:28 +00:00
|
|
|
result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-12-02 01:04:28 -08:00
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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->delegating && ((node != search.qpdb->origin &&
|
|
|
|
!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...
|
|
|
|
*/
|
|
|
|
|
2025-08-12 07:47:03 +02:00
|
|
|
sigpair = DNS_SIGTYPEPAIR(type);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
empty_node = true;
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* Look for an active, extant rdataset.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if (header->serial <= search.serial && !IGNORE(header))
|
|
|
|
{
|
2025-08-12 11:31:57 +02:00
|
|
|
if (!EXISTS(header)) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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.
|
|
|
|
*/
|
2025-08-06 19:34:35 +02:00
|
|
|
if (maybe_zonecut &&
|
2025-08-05 18:05:52 +02:00
|
|
|
top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns))
|
2025-08-06 19:34:35 +02:00
|
|
|
{
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* We increment the reference count on node to
|
|
|
|
* ensure that search->zonecut_header will
|
|
|
|
* still be valid later.
|
|
|
|
*/
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(search.qpdb,
|
|
|
|
node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_nsec3) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
!matchparams(header, &search))
|
|
|
|
{
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
goto partial_match;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we found a type we were looking for,
|
|
|
|
* remember it.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair == type ||
|
2025-08-06 19:34:35 +02:00
|
|
|
type == dns_rdatatype_any ||
|
2025-08-05 18:05:52 +02:00
|
|
|
(top->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_cname) &&
|
2025-08-06 19:34:35 +02:00
|
|
|
cname_ok))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We've found the answer!
|
|
|
|
*/
|
|
|
|
found = header;
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_cname) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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 {
|
2025-08-12 07:47:03 +02:00
|
|
|
sigpair = DNS_SIGTYPEPAIR(
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_rdatatype_cname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we've got all we need, end the search.
|
|
|
|
*/
|
|
|
|
if (!maybe_zonecut && foundsig != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair == sigpair) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair ==
|
|
|
|
DNS_TYPEPAIR(dns_rdatatype_nsec) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
!search.version->havensec3)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Remember a NSEC rdataset even if we're
|
|
|
|
* not specifically looking for it, because
|
|
|
|
* we might need it later.
|
|
|
|
*/
|
|
|
|
nsecheader = header;
|
2025-08-05 18:05:52 +02:00
|
|
|
} else if (top->typepair ==
|
2025-08-12 07:47:03 +02:00
|
|
|
DNS_SIGTYPEPAIR(
|
|
|
|
dns_rdatatype_nsec) &&
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
!search.version->havensec3)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If we need the NSEC rdataset, we'll also
|
|
|
|
* need its signature.
|
|
|
|
*/
|
|
|
|
nsecsig = header;
|
|
|
|
} else if (cname_ok &&
|
2025-08-05 18:05:52 +02:00
|
|
|
top->typepair ==
|
2025-08-12 07:47:03 +02:00
|
|
|
DNS_SIGTYPEPAIR(dns_rdatatype_cname))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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
|
2024-12-19 14:19:43 -08:00
|
|
|
* this node doesn't exist in the desired version.
|
|
|
|
* If there's a node above this one, reassign the
|
|
|
|
* foundname to the parent and treat this as a partial
|
|
|
|
* match.
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
*/
|
|
|
|
if (!wild) {
|
2024-12-19 14:19:43 -08:00
|
|
|
unsigned int len = search.chain.len - 1;
|
|
|
|
if (len > 0) {
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2024-12-19 14:19:43 -08:00
|
|
|
dns_qpchain_node(&search.chain, len - 1, NULL,
|
|
|
|
(void **)&node, NULL);
|
|
|
|
dns_name_copy(&node->name, foundname);
|
|
|
|
goto partial_match;
|
|
|
|
}
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2024-11-14 11:18:00 +01:00
|
|
|
result = qpzone_setup_delegation(
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
&search, nodep, foundname, rdataset,
|
|
|
|
sigrdataset DNS__DB_FLARG_PASS);
|
|
|
|
goto tree_exit;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* The desired type doesn't exist.
|
|
|
|
*/
|
|
|
|
result = DNS_R_NXRRSET;
|
|
|
|
if (search.version->secure && !search.version->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;
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
result = find_closest_nsec(
|
|
|
|
&search, nodep, foundname, rdataset,
|
|
|
|
sigrdataset, false,
|
|
|
|
search.version->secure DNS__DB_FLARG_PASS);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = DNS_R_EMPTYWILD;
|
|
|
|
}
|
|
|
|
goto tree_exit;
|
|
|
|
}
|
|
|
|
if (nodep != NULL) {
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(search.qpdb, node DNS__DB_FLARG_PASS);
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
if (search.version->secure && !search.version->havensec3) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(search.qpdb, node, nsecheader,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
rdataset DNS__DB_FLARG_PASS);
|
|
|
|
if (nsecsig != NULL) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(search.qpdb, node, nsecsig,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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.
|
|
|
|
*/
|
2025-08-06 19:34:35 +02:00
|
|
|
if (type != found->typepair && type != dns_rdatatype_any &&
|
2025-08-05 18:05:52 +02:00
|
|
|
found->typepair == DNS_TYPEPAIR(dns_rdatatype_cname))
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-08-11 10:06:33 +02:00
|
|
|
if (dns_rdatatype_isnsec(type) ||
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
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) {
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(search.qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
} else {
|
|
|
|
search.need_cleanup = false;
|
|
|
|
}
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)node;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type != dns_rdatatype_any) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(search.qpdb, node, found,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
rdataset DNS__DB_FLARG_PASS);
|
|
|
|
if (foundsig != NULL) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(search.qpdb, node, foundsig,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
sigrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wild) {
|
|
|
|
foundname->attributes.wildcard = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
node_exit:
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
tree_exit:
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpread_destroy(qpdb->tree, &search.qpr);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(search.qpdb, node, 0,
|
|
|
|
&nlocktype DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (close_version) {
|
|
|
|
closeversion(db, &version, false DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode,
|
|
|
|
dns_dbversion_t *dbversion, unsigned int options,
|
|
|
|
isc_stdtime_t now ISC_ATTR_UNUSED,
|
|
|
|
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
2023-11-15 08:55:18 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2023-11-15 08:55:18 -08:00
|
|
|
qpdb_rdatasetiter_t *iterator = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
if (version == NULL) {
|
|
|
|
currentversion(db, (dns_dbversion_t **)(void *)(&version));
|
2023-11-15 08:55:18 -08:00
|
|
|
} else {
|
2024-03-12 11:32:29 -07:00
|
|
|
INSIST(version->qpdb == qpdb);
|
|
|
|
isc_refcount_increment(&version->references);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
2024-03-12 11:32:29 -07:00
|
|
|
iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
|
|
|
|
*iterator = (qpdb_rdatasetiter_t){
|
|
|
|
.common.methods = &rdatasetiter_methods,
|
|
|
|
.common.db = db,
|
2024-11-05 16:13:10 +01:00
|
|
|
.common.node = (dns_dbnode_t *)node,
|
2024-03-12 11:32:29 -07:00
|
|
|
.common.version = (dns_dbversion_t *)version,
|
|
|
|
.common.options = options,
|
|
|
|
.common.magic = DNS_RDATASETITER_MAGIC,
|
|
|
|
};
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
*iteratorp = (dns_rdatasetiter_t *)iterator;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpzone_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)source;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpzonedb_t *qpdb = node->qpdb;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2023-12-02 01:04:28 -08:00
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpzone_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = NULL;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpzonedb_t *qpdb;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
REQUIRE(nodep != NULL && *nodep != NULL);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
node = (qpznode_t *)(*nodep);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
qpdb = node->qpdb;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2025-01-27 21:07:11 +01:00
|
|
|
*nodep = NULL;
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
/*
|
2025-02-24 15:55:18 +01:00
|
|
|
* qpzone_destroy() uses call_rcu() API to destroy the node locks, so it
|
|
|
|
* is safe to call it in the middle of NODE_LOCK, but we need to acquire
|
|
|
|
* the database reference to prevent destroying the database while the
|
|
|
|
* NODE_LOCK is locked.
|
2025-01-30 14:42:57 -08:00
|
|
|
*/
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-02-24 15:55:18 +01:00
|
|
|
qpzonedb_ref(qpdb);
|
|
|
|
|
2025-02-04 18:02:29 +01:00
|
|
|
rcu_read_lock();
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2025-02-04 18:02:29 +01:00
|
|
|
rcu_read_unlock();
|
2025-02-24 15:55:18 +01:00
|
|
|
|
|
|
|
qpzonedb_unref(qpdb);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static unsigned int
|
2025-05-26 11:34:16 +02:00
|
|
|
nodecount(dns_db_t *db, dns_dbtree_t tree ISC_ATTR_UNUSED) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
dns_qp_memusage_t mu;
|
|
|
|
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
mu = dns_qpmulti_memusage(qpdb->tree);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
return mu.leaves;
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
|
|
|
setloop(dns_db_t *db, isc_loop_t *loop) {
|
|
|
|
qpzonedb_t *qpdb = NULL;
|
|
|
|
|
|
|
|
qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
|
|
|
RWLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
if (qpdb->loop != NULL) {
|
|
|
|
isc_loop_detach(&qpdb->loop);
|
|
|
|
}
|
|
|
|
if (loop != NULL) {
|
|
|
|
isc_loop_attach(loop, &qpdb->loop);
|
|
|
|
}
|
|
|
|
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(nodep != NULL && *nodep == NULL);
|
|
|
|
|
|
|
|
/* Note that the access to the origin node doesn't require a DB lock */
|
2024-11-05 16:13:10 +01:00
|
|
|
INSIST(qpdb->origin != NULL);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, qpdb->origin DNS__DB_FLARG_PASS);
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)qpdb->origin;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
locknode(dns_dbnode_t *dbnode, isc_rwlocktype_t type) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
RWLOCK(qpzone_get_lock(node), type);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
unlocknode(dns_dbnode_t *dbnode, isc_rwlocktype_t type) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
RWUNLOCK(qpzone_get_lock(node), type);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
dns_slabheader_t *header = data;
|
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
if (header->heap_index != 0) {
|
|
|
|
LOCK(get_heap_lock(header));
|
|
|
|
isc_heap_delete(HEADERNODE(header)->heap->heap,
|
|
|
|
header->heap_index);
|
|
|
|
UNLOCK(get_heap_lock(header));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
header->heap_index = 0;
|
|
|
|
}
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
/*
|
|
|
|
* Rdataset Iterator Methods
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
|
|
|
qpdb_rdatasetiter_t *qrditer = NULL;
|
|
|
|
|
|
|
|
qrditer = (qpdb_rdatasetiter_t *)(*iteratorp);
|
|
|
|
|
|
|
|
if (qrditer->common.version != NULL) {
|
|
|
|
closeversion(qrditer->common.db, &qrditer->common.version,
|
|
|
|
false DNS__DB_FLARG_PASS);
|
|
|
|
}
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
dns__db_detachnode(&qrditer->common.node DNS__DB_FLARG_PASS);
|
2023-11-15 08:55:18 -08:00
|
|
|
isc_mem_put(qrditer->common.db->mctx, qrditer, sizeof(*qrditer));
|
|
|
|
|
|
|
|
*iteratorp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
|
|
|
|
qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
|
2024-11-05 16:13:10 +01:00
|
|
|
qpznode_t *node = (qpznode_t *)qrditer->common.node;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
|
2023-11-15 08:55:18 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *found = NULL;
|
|
|
|
dns_slabtop_t *top = NULL;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
while (header != NULL &&
|
|
|
|
(IGNORE(header) || header->serial > version->serial))
|
|
|
|
{
|
|
|
|
header = header->down;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header != NULL && EXISTS(header)) {
|
|
|
|
found = header;
|
2023-11-15 08:55:18 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
qrditer->currenttop = top;
|
|
|
|
qrditer->current = found;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top == NULL) {
|
2023-11-15 08:55:18 -08:00
|
|
|
return ISC_R_NOMORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
|
|
|
|
qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
|
2024-11-05 16:13:10 +01:00
|
|
|
qpznode_t *node = (qpznode_t *)qrditer->common.node;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
|
2023-11-15 08:55:18 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-05-07 14:52:11 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(node);
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = qrditer->currenttop;
|
|
|
|
dns_slabheader_t *found = NULL;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top == NULL) {
|
2023-11-15 08:55:18 -08:00
|
|
|
return ISC_R_NOMORE;
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
/*
|
2025-01-31 15:47:33 +01:00
|
|
|
* Find the start of the header chain for the next type.
|
2023-11-15 08:55:18 -08:00
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = top->next; top != NULL; top = top->next) {
|
|
|
|
dns_slabheader_t *header = top->header;
|
|
|
|
while (header != NULL &&
|
|
|
|
(IGNORE(header) || header->serial > version->serial))
|
|
|
|
{
|
|
|
|
header = header->down;
|
|
|
|
}
|
2025-01-31 15:47:33 +01:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (header != NULL && EXISTS(header)) {
|
|
|
|
found = header;
|
2023-11-15 08:55:18 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
qrditer->currenttop = top;
|
|
|
|
qrditer->current = found;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
if (top == NULL) {
|
2023-11-15 08:55:18 -08:00
|
|
|
return ISC_R_NOMORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdatasetiter_current(dns_rdatasetiter_t *iterator,
|
|
|
|
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
|
|
|
qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db);
|
2025-08-05 18:05:52 +02:00
|
|
|
qpznode_t *qpnode = (qpznode_t *)qrditer->common.node;
|
2023-11-15 08:55:18 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-08-05 18:05:52 +02:00
|
|
|
isc_rwlock_t *nlock = qpzone_get_lock(qpnode);
|
|
|
|
dns_slabheader_t *header = qrditer->current;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
REQUIRE(header != NULL);
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
bindrdataset(qpdb, qpnode, header, rdataset DNS__DB_FLARG_PASS);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Database Iterator Methods
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
reference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iter->common.db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = iter->node;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
if (node == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dereference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iter->common.db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = iter->node;
|
2023-11-15 08:55:18 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
if (node == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
iter->node = NULL;
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
|
|
|
|
NODE_RDLOCK(nlock, &nlocktype);
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_release(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) {
|
|
|
|
qpdb_dbiterator_t *iter = (qpdb_dbiterator_t *)(*iteratorp);
|
|
|
|
dns_db_t *db = NULL;
|
|
|
|
|
|
|
|
dereference_iter_node(iter DNS__DB_FLARG_PASS);
|
|
|
|
|
|
|
|
dns_db_attach(iter->common.db, &db);
|
|
|
|
dns_db_detach(&iter->common.db);
|
|
|
|
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpsnap_destroy(qpdb->tree, &iter->snap);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
isc_mem_put(db->mctx, iter, sizeof(*iter));
|
|
|
|
dns_db_detach(&db);
|
|
|
|
|
|
|
|
*iteratorp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) {
|
|
|
|
isc_result_t result;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS &&
|
|
|
|
qpdbiter->result != ISC_R_NOTFOUND &&
|
|
|
|
qpdbiter->result != DNS_R_PARTIALMATCH &&
|
|
|
|
qpdbiter->result != ISC_R_NOMORE)
|
|
|
|
{
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpiter_init(qpdbiter->snap, &qpdbiter->iter);
|
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
switch (qpdbiter->nsec3mode) {
|
2025-05-26 11:34:16 +02:00
|
|
|
case nonsec3:
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* If we immediately hit an NSEC/NSEC3 node,
|
|
|
|
* we don't have any non-nsec nodes.
|
|
|
|
*/
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NORMAL) {
|
2025-05-26 11:34:16 +02:00
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case full:
|
2025-05-26 11:34:16 +02:00
|
|
|
/* skip the NSEC3 origin node. */
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we hit an NSEC node, we need to start at the NSEC3 part of
|
|
|
|
* the tree.
|
|
|
|
*/
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
}
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case nsec3only:
|
|
|
|
/*
|
|
|
|
* NSEC3 follows after all non-nsec3 nodes, seek the NSEC3
|
|
|
|
* origin node.
|
|
|
|
*/
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC3, NULL,
|
|
|
|
&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
if (result != ISC_R_SUCCESS ||
|
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
|
|
|
/* skip the NSEC3 origin node (or its predecessor) */
|
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
2023-11-15 08:55:18 -08:00
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
} else {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
}
|
|
|
|
qpdbiter->result = result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG) {
|
|
|
|
isc_result_t result;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS &&
|
|
|
|
qpdbiter->result != ISC_R_NOTFOUND &&
|
|
|
|
qpdbiter->result != DNS_R_PARTIALMATCH &&
|
|
|
|
qpdbiter->result != ISC_R_NOMORE)
|
|
|
|
{
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpiter_init(qpdbiter->snap, &qpdbiter->iter);
|
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
|
|
|
|
2023-11-15 08:55:18 -08:00
|
|
|
switch (qpdbiter->nsec3mode) {
|
|
|
|
case nsec3only:
|
2025-05-26 11:34:16 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) {
|
|
|
|
/* tree only has NSEC3 origin node. */
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
2025-07-07 11:29:45 +02:00
|
|
|
} else if (qpdbiter->node->nspace !=
|
|
|
|
DNS_DBNAMESPACE_NSEC3)
|
2025-05-26 17:36:33 +02:00
|
|
|
{
|
2025-05-26 11:34:16 +02:00
|
|
|
/* tree has no NSEC3 nodes at all. */
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
|
|
|
}
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case full:
|
2025-05-26 11:34:16 +02:00
|
|
|
/* skip the NSEC3 origin node. */
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
2023-11-15 08:55:18 -08:00
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
2025-05-26 11:34:16 +02:00
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2023-11-15 08:55:18 -08:00
|
|
|
qpdbiter->node = NULL;
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we hit an NSEC node, we need to seek the final normal node
|
|
|
|
* of the tree.
|
|
|
|
*/
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
}
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case nonsec3:
|
|
|
|
/*
|
|
|
|
* The final non-nsec node is before the the NSEC origin node.
|
|
|
|
*/
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC, NULL,
|
|
|
|
&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
INSIST(QPDBITER_NSEC_ORIGIN_NODE(qpdb, qpdbiter));
|
|
|
|
/* skip the NSEC origin node */
|
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
2023-11-15 08:55:18 -08:00
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* The NSEC origin node was not found, but the iterator
|
|
|
|
* should point to its predecessor, which is the node we
|
|
|
|
* want.
|
|
|
|
*/
|
|
|
|
result = dns_qpiter_current(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace ==
|
|
|
|
DNS_DBNAMESPACE_NORMAL);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
} else {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
}
|
|
|
|
qpdbiter->result = result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_seek(dns_dbiterator_t *iterator,
|
|
|
|
const dns_name_t *name DNS__DB_FLARG) {
|
|
|
|
isc_result_t result, tresult;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS &&
|
|
|
|
qpdbiter->result != ISC_R_NOTFOUND &&
|
|
|
|
qpdbiter->result != DNS_R_PARTIALMATCH &&
|
|
|
|
qpdbiter->result != ISC_R_NOMORE)
|
|
|
|
{
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
|
|
|
|
switch (qpdbiter->nsec3mode) {
|
|
|
|
case nsec3only:
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_lookup(
|
|
|
|
qpdbiter->snap, name, DNS_DBNAMESPACE_NSEC3, NULL,
|
|
|
|
&qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
|
2023-11-15 08:55:18 -08:00
|
|
|
break;
|
|
|
|
case nonsec3:
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_lookup(
|
|
|
|
qpdbiter->snap, name, DNS_DBNAMESPACE_NORMAL, NULL,
|
|
|
|
&qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
|
2023-11-15 08:55:18 -08:00
|
|
|
break;
|
|
|
|
case full:
|
2025-07-07 11:29:45 +02:00
|
|
|
result = dns_qp_lookup(
|
|
|
|
qpdbiter->snap, name, DNS_DBNAMESPACE_NORMAL, NULL,
|
|
|
|
&qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2025-05-27 10:57:11 +02:00
|
|
|
tresult = dns_qp_lookup(qpdbiter->snap, name,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC3, NULL,
|
2025-05-27 10:57:11 +02:00
|
|
|
&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
2023-11-15 08:55:18 -08:00
|
|
|
if (tresult == ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
|
|
|
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
} else {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
qpdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS
|
|
|
|
: result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
|
|
|
|
isc_result_t result;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
|
|
|
|
|
|
|
|
REQUIRE(qpdbiter->node != NULL);
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS) {
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
2023-11-15 08:55:18 -08:00
|
|
|
(void **)&qpdbiter->node, NULL);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
switch (qpdbiter->nsec3mode) {
|
|
|
|
case nsec3only:
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
2023-11-15 08:55:18 -08:00
|
|
|
if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) {
|
2025-05-26 11:34:16 +02:00
|
|
|
/* we hit the NSEC3 origin node. */
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
2025-07-07 11:29:45 +02:00
|
|
|
} else if (qpdbiter->node->nspace !=
|
|
|
|
DNS_DBNAMESPACE_NSEC3)
|
2025-05-26 17:36:33 +02:00
|
|
|
{
|
2025-05-26 11:34:16 +02:00
|
|
|
/* we hit a non-NSEC3 node. */
|
2023-11-15 08:55:18 -08:00
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
|
|
|
}
|
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
case full:
|
|
|
|
/* skip the NSEC3 origin node. */
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we hit an NSEC node, we need to seek the final normal node
|
|
|
|
* of the tree.
|
|
|
|
*/
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC, NULL,
|
|
|
|
&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
INSIST(QPDBITER_NSEC_ORIGIN_NODE(qpdb, qpdbiter));
|
|
|
|
/* skip the NSEC origin node */
|
|
|
|
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
|
2023-11-15 08:55:18 -08:00
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* The NSEC origin node was not found, but the iterator
|
|
|
|
* should point to its predecessor, which is the node we
|
|
|
|
* want.
|
|
|
|
*/
|
|
|
|
result = dns_qpiter_current(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace ==
|
|
|
|
DNS_DBNAMESPACE_NORMAL);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
case nonsec3:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
} else {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
qpdbiter->result = result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
|
|
|
|
isc_result_t result;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
|
|
|
|
|
|
|
|
REQUIRE(qpdbiter->node != NULL);
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS) {
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
2023-11-15 08:55:18 -08:00
|
|
|
(void **)&qpdbiter->node, NULL);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
switch (qpdbiter->nsec3mode) {
|
|
|
|
case nonsec3:
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/* we hit an NSEC or NSEC3 node. */
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NORMAL) {
|
2025-05-26 11:34:16 +02:00
|
|
|
qpdbiter->node = NULL;
|
|
|
|
result = ISC_R_NOMORE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case full:
|
|
|
|
/* skip the NSEC3 origin node. */
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
/*
|
2025-05-26 11:34:16 +02:00
|
|
|
* If we hit an NSEC node, we need to start at the NSEC3 part of
|
|
|
|
* the tree.
|
2023-11-15 08:55:18 -08:00
|
|
|
*/
|
2025-07-07 11:29:45 +02:00
|
|
|
if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
}
|
2025-07-07 11:29:45 +02:00
|
|
|
INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
|
2025-05-26 11:34:16 +02:00
|
|
|
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC3, NULL,
|
|
|
|
&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
if (result != ISC_R_SUCCESS ||
|
|
|
|
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
|
|
|
|
{
|
|
|
|
/* skip the NSEC3 origin node (or its predecessor). */
|
|
|
|
result = dns_qpiter_next(&qpdbiter->iter, NULL,
|
|
|
|
(void **)&qpdbiter->node,
|
|
|
|
NULL);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
2025-05-26 11:34:16 +02:00
|
|
|
break;
|
|
|
|
case nsec3only:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
|
|
|
|
} else {
|
|
|
|
qpdbiter->node = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
qpdbiter->result = result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
|
|
|
|
dns_name_t *name DNS__DB_FLARG) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = qpdbiter->node;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
REQUIRE(qpdbiter->result == ISC_R_SUCCESS);
|
|
|
|
REQUIRE(qpdbiter->node != NULL);
|
|
|
|
|
|
|
|
if (name != NULL) {
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&qpdbiter->node->name, name);
|
2023-11-15 08:55:18 -08:00
|
|
|
}
|
|
|
|
|
2025-01-30 14:42:57 -08:00
|
|
|
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2024-11-05 16:13:10 +01:00
|
|
|
*nodep = (dns_dbnode_t *)qpdbiter->node;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_pause(dns_dbiterator_t *iterator ISC_ATTR_UNUSED) {
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
|
|
|
|
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
|
|
|
|
|
|
|
|
if (qpdbiter->result != ISC_R_SUCCESS) {
|
|
|
|
return qpdbiter->result;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_name_copy(dns_rootname, name);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_createiterator(dns_db_t *db, unsigned int options,
|
|
|
|
dns_dbiterator_t **iteratorp) {
|
2023-11-15 08:55:18 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
qpdb_dbiterator_t *iter = NULL;
|
2025-05-26 11:34:16 +02:00
|
|
|
isc_result_t result;
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
|
|
|
iter = isc_mem_get(qpdb->common.mctx, sizeof(*iter));
|
|
|
|
*iter = (qpdb_dbiterator_t){
|
|
|
|
.common.magic = DNS_DBITERATOR_MAGIC,
|
|
|
|
.common.methods = &dbiterator_methods,
|
|
|
|
.common.relative_names = ((options & DNS_DB_RELATIVENAMES) !=
|
|
|
|
0),
|
|
|
|
};
|
|
|
|
|
|
|
|
if ((options & DNS_DB_NSEC3ONLY) != 0) {
|
|
|
|
iter->nsec3mode = nsec3only;
|
|
|
|
} else if ((options & DNS_DB_NONSEC3) != 0) {
|
|
|
|
iter->nsec3mode = nonsec3;
|
|
|
|
} else {
|
|
|
|
iter->nsec3mode = full;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_db_attach(db, &iter->common.db);
|
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_snapshot(qpdb->tree, &iter->snap);
|
2023-11-15 08:55:18 -08:00
|
|
|
|
2025-05-26 11:34:16 +02:00
|
|
|
switch (iter->nsec3mode) {
|
|
|
|
case nonsec3:
|
|
|
|
case full:
|
|
|
|
dns_qpiter_init(iter->snap, &iter->iter);
|
|
|
|
break;
|
|
|
|
case nsec3only:
|
|
|
|
/*
|
|
|
|
* NSEC3 follows after all non-nsec3 nodes,
|
|
|
|
* seek the NSEC3 origin node.
|
|
|
|
*/
|
2025-05-27 10:57:11 +02:00
|
|
|
result = dns_qp_lookup(iter->snap, &qpdb->common.origin,
|
2025-07-07 11:29:45 +02:00
|
|
|
DNS_DBNAMESPACE_NSEC3, NULL, &iter->iter,
|
2025-05-27 10:57:11 +02:00
|
|
|
NULL, NULL, NULL);
|
2025-05-26 11:34:16 +02:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2023-11-15 08:55:18 -08:00
|
|
|
|
|
|
|
*iteratorp = (dns_dbiterator_t *)iter;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_addrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
|
|
|
dns_dbversion_t *dbversion,
|
|
|
|
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
|
|
|
unsigned int options,
|
|
|
|
dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_result_t result;
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_region_t region;
|
|
|
|
dns_slabheader_t *newheader = NULL;
|
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_fixedname_t fn;
|
|
|
|
dns_name_t *name = dns_fixedname_initname(&fn);
|
|
|
|
dns_qp_t *nsec = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2024-03-19 17:02:56 +11:00
|
|
|
REQUIRE(version != NULL && version->qpdb == qpdb);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* SOA records are only allowed at top of zone.
|
|
|
|
*/
|
|
|
|
if (rdataset->type == dns_rdatatype_soa && node != qpdb->origin) {
|
|
|
|
return DNS_R_NOTZONETOP;
|
|
|
|
}
|
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
REQUIRE((node->nspace == DNS_DBNAMESPACE_NSEC3 &&
|
2023-11-19 00:00:49 -08:00
|
|
|
(rdataset->type == dns_rdatatype_nsec3 ||
|
|
|
|
rdataset->covers == dns_rdatatype_nsec3)) ||
|
2025-07-07 11:29:45 +02:00
|
|
|
(node->nspace != DNS_DBNAMESPACE_NSEC3 &&
|
2023-11-19 00:00:49 -08:00
|
|
|
rdataset->type != dns_rdatatype_nsec3 &&
|
|
|
|
rdataset->covers != dns_rdatatype_nsec3));
|
|
|
|
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion,
|
|
|
|
qpdb->maxrrperset);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-29 16:24:48 +09:00
|
|
|
if (result == DNS_R_TOOMANYRECORDS) {
|
|
|
|
dns__db_logtoomanyrecords((dns_db_t *)qpdb, &node->name,
|
|
|
|
rdataset->type, "adding",
|
|
|
|
qpdb->maxrrperset);
|
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&node->name, name);
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_rdataset_getownercase(rdataset, name);
|
|
|
|
|
|
|
|
newheader = (dns_slabheader_t *)region.base;
|
2025-07-15 12:16:39 +02:00
|
|
|
dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
|
2025-02-03 14:06:37 +01:00
|
|
|
newheader->ttl = rdataset->ttl;
|
2023-11-19 00:00:49 -08:00
|
|
|
if (rdataset->ttl == 0U) {
|
|
|
|
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL);
|
|
|
|
}
|
2025-02-07 21:06:34 -08:00
|
|
|
|
2023-11-19 00:00:49 -08:00
|
|
|
atomic_init(&newheader->count,
|
|
|
|
atomic_fetch_add_relaxed(&init_count, 1));
|
2024-03-19 17:02:56 +11:00
|
|
|
|
|
|
|
newheader->serial = version->serial;
|
2025-07-09 16:56:22 +02:00
|
|
|
if (rdataset->attributes.resign) {
|
2024-03-19 17:02:56 +11:00
|
|
|
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
|
|
|
|
newheader->resign =
|
|
|
|
(isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
|
|
|
|
1);
|
|
|
|
newheader->resign_lsb = rdataset->resign & 0x1;
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add to the auxiliary NSEC tree if we're adding an NSEC record.
|
|
|
|
*/
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
if (!node->havensec && rdataset->type == dns_rdatatype_nsec) {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_write(qpdb->tree, &nsec);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're adding a delegation type or adding to the auxiliary NSEC
|
|
|
|
* tree hold an exclusive lock on the tree. In the latter case the
|
|
|
|
* lock does not necessarily have to be acquired but it will help
|
|
|
|
* purge ancient entries more effectively.
|
|
|
|
*
|
|
|
|
* (Note: node lock must be acquired after starting
|
|
|
|
* the QPDB transaction and released before committing.)
|
|
|
|
*/
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
|
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
if (nsec != NULL) {
|
Prepend qpkey with denial byte
In preparation to merge the three qp tries (tree, nsec, nsec3) into
one, add the piece of information into the qpkey. This is the most
significant bit of information, so prepend the denial type to the qpkey.
This means we need to pass on the denial type when constructing the
qpkey from a name, or doing a lookup.
Reuse the the DNS_DB_NSEC_* values. Most qp tries in the code we just
pass on 0 (nta, rpz, zt, etc.), because there is no need for denial of
existence, but for qpzone and qpcache we must pass the right value.
Change the code, so that node->nsec no longer can have the value
DNS_DB_NSEC_HAS_NSEC, instead track this in a new attribute 'havensec'.
Since we use node->nsec to convert names to keys, the value MUST be set
before inserting the node into the qp-trie.
Update the fuzzing and unit tests accordingly. This only adds a few
extra test cases, more are needed.
In the qp_test.c we can remove test code for empty keys as this is
no longer possible.
2025-04-25 17:21:16 +02:00
|
|
|
node->havensec = true;
|
2025-02-11 16:08:29 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If it fails, there was already an NSEC node,
|
|
|
|
* so we can detach the new one we created and
|
|
|
|
* move on.
|
|
|
|
*/
|
2025-07-07 11:42:17 +02:00
|
|
|
qpznode_t *nsecnode = new_qpznode(qpdb, name,
|
|
|
|
DNS_DBNAMESPACE_NSEC);
|
2025-02-11 16:08:29 -08:00
|
|
|
(void)dns_qp_insert(nsec, nsecnode, 0);
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_detach(&nsecnode);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = add(qpdb, node, name, version, newheader, options,
|
2024-03-12 11:32:29 -07:00
|
|
|
false, addedrdataset, 0 DNS__DB_FLARG_PASS);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're adding a delegation type (e.g. NS or DNAME),
|
|
|
|
* then we need to set the callback bit on the node.
|
|
|
|
*/
|
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
delegating_type(qpdb, node, rdataset->type))
|
|
|
|
{
|
2024-05-14 12:36:58 -07:00
|
|
|
node->delegating = true;
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
if (nsec != NULL) {
|
2025-05-26 11:34:16 +02:00
|
|
|
dns_qpmulti_commit(qpdb->tree, &nsec);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
|
|
|
dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
|
|
|
|
unsigned int options,
|
|
|
|
dns_rdataset_t *newrdataset DNS__DB_FLARG) {
|
2023-11-19 00:00:49 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2023-11-19 00:00:49 -08:00
|
|
|
dns_fixedname_t fname;
|
|
|
|
dns_name_t *nodename = dns_fixedname_initname(&fname);
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL;
|
|
|
|
dns_slabheader_t *newheader = NULL;
|
2025-02-07 21:21:52 -08:00
|
|
|
dns_slabheader_t *subresult = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_region_t region;
|
|
|
|
isc_result_t result;
|
2024-04-29 15:45:26 -07:00
|
|
|
qpz_changed_t *changed = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
REQUIRE(version != NULL && version->qpdb == qpdb);
|
|
|
|
|
2025-07-07 11:29:45 +02:00
|
|
|
REQUIRE((node->nspace == DNS_DBNAMESPACE_NSEC3 &&
|
2023-11-19 00:00:49 -08:00
|
|
|
(rdataset->type == dns_rdatatype_nsec3 ||
|
|
|
|
rdataset->covers == dns_rdatatype_nsec3)) ||
|
2025-07-07 11:29:45 +02:00
|
|
|
(node->nspace != DNS_DBNAMESPACE_NSEC3 &&
|
2023-11-19 00:00:49 -08:00
|
|
|
rdataset->type != dns_rdatatype_nsec3 &&
|
|
|
|
rdataset->covers != dns_rdatatype_nsec3));
|
|
|
|
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&node->name, nodename);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion, 0);
|
2023-11-19 00:00:49 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
newheader = (dns_slabheader_t *)region.base;
|
2025-07-15 12:16:39 +02:00
|
|
|
dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
|
2025-02-03 14:06:37 +01:00
|
|
|
newheader->ttl = rdataset->ttl;
|
2023-11-19 00:00:49 -08:00
|
|
|
atomic_init(&newheader->attributes, 0);
|
|
|
|
newheader->serial = version->serial;
|
|
|
|
atomic_init(&newheader->count,
|
|
|
|
atomic_fetch_add_relaxed(&init_count, 1));
|
2025-07-09 16:56:22 +02:00
|
|
|
if (rdataset->attributes.resign) {
|
2023-11-19 00:00:49 -08:00
|
|
|
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
|
|
|
|
newheader->resign =
|
|
|
|
(isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
|
|
|
|
1);
|
|
|
|
newheader->resign_lsb = rdataset->resign & 0x1;
|
|
|
|
}
|
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
changed = add_changed(newheader, version DNS__DB_FLARG_PASS);
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top->next) {
|
|
|
|
if (top->typepair == newheader->typepair) {
|
2023-11-19 00:00:49 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *header = NULL;
|
|
|
|
if (top != NULL) {
|
|
|
|
header = top->header;
|
|
|
|
while (header != NULL && IGNORE(header)) {
|
|
|
|
header = header->down;
|
|
|
|
}
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
2025-08-12 11:31:57 +02:00
|
|
|
if (header != NULL && EXISTS(header)) {
|
2023-11-19 00:00:49 -08:00
|
|
|
unsigned int flags = 0;
|
|
|
|
subresult = NULL;
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
if ((options & DNS_DBSUB_EXACT) != 0) {
|
|
|
|
flags |= DNS_RDATASLAB_EXACT;
|
2025-02-03 14:06:37 +01:00
|
|
|
if (newheader->ttl != header->ttl) {
|
2023-11-19 00:00:49 -08:00
|
|
|
result = DNS_R_NOTEXACT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = dns_rdataslab_subtract(
|
2025-02-07 21:21:52 -08:00
|
|
|
header, newheader, qpdb->common.mctx,
|
|
|
|
qpdb->common.rdclass,
|
2025-08-05 18:05:52 +02:00
|
|
|
DNS_TYPEPAIR_TYPE(top->typepair), flags,
|
2023-11-19 00:00:49 -08:00
|
|
|
&subresult);
|
|
|
|
}
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
dns_slabheader_destroy(&newheader);
|
2025-02-07 21:21:52 -08:00
|
|
|
newheader = subresult;
|
2025-07-15 12:16:39 +02:00
|
|
|
dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
|
2023-11-19 00:00:49 -08:00
|
|
|
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;
|
2025-07-08 16:29:56 +02:00
|
|
|
resigninsert(newheader);
|
2023-11-19 00:00:49 -08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We have to set the serial since the rdataslab
|
|
|
|
* subtraction routine copies the reserved portion of
|
|
|
|
* header, not newheader.
|
|
|
|
*/
|
|
|
|
newheader->serial = version->serial;
|
|
|
|
/*
|
|
|
|
* XXXJT: dns_rdataslab_subtract() copied the pointers
|
|
|
|
* to additional info. We need to clear these fields
|
|
|
|
* to avoid having duplicated references.
|
|
|
|
*/
|
|
|
|
maybe_update_recordsandsize(true, version, 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);
|
2025-08-05 18:05:52 +02:00
|
|
|
newheader = dns_slabheader_new(db->mctx,
|
2023-11-19 00:00:49 -08:00
|
|
|
(dns_dbnode_t *)node);
|
2025-02-03 14:06:37 +01:00
|
|
|
newheader->ttl = 0;
|
2025-08-05 18:05:52 +02:00
|
|
|
newheader->typepair = top->typepair;
|
2023-11-19 00:00:49 -08:00
|
|
|
atomic_init(&newheader->attributes,
|
|
|
|
DNS_SLABHEADERATTR_NONEXISTENT);
|
|
|
|
newheader->serial = version->serial;
|
|
|
|
} else {
|
|
|
|
dns_slabheader_destroy(&newheader);
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2025-08-05 18:05:52 +02:00
|
|
|
* If we're here, we want to link newheader at the top.
|
2023-11-19 00:00:49 -08:00
|
|
|
*/
|
2025-08-05 18:05:52 +02:00
|
|
|
INSIST(version->serial >= top->header->serial);
|
2023-11-19 00:00:49 -08:00
|
|
|
maybe_update_recordsandsize(false, version, header,
|
|
|
|
nodename->length);
|
2025-08-05 18:05:52 +02:00
|
|
|
|
|
|
|
newheader->top = top;
|
|
|
|
newheader->down = top->header;
|
|
|
|
top->header = newheader;
|
|
|
|
|
2024-05-14 12:36:58 -07:00
|
|
|
node->dirty = true;
|
2023-11-19 00:00:49 -08:00
|
|
|
changed->dirty = true;
|
|
|
|
resigndelete(qpdb, version, 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) {
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(qpdb, node, newheader,
|
2023-11-19 00:00:49 -08:00
|
|
|
newrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == DNS_R_NXRRSET && newrdataset != NULL &&
|
|
|
|
(options & DNS_DBSUB_WANTOLD) != 0)
|
|
|
|
{
|
2025-02-03 14:06:37 +01:00
|
|
|
bindrdataset(qpdb, node, header,
|
2023-11-19 00:00:49 -08:00
|
|
|
newrdataset DNS__DB_FLARG_PASS);
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock:
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2024-11-14 11:18:00 +01:00
|
|
|
qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
|
|
|
dns_dbversion_t *dbversion, dns_rdatatype_t type,
|
|
|
|
dns_rdatatype_t covers DNS__DB_FLARG) {
|
2023-11-19 00:00:49 -08:00
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)dbnode;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2023-11-19 00:00:49 -08:00
|
|
|
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;
|
2025-01-27 21:07:11 +01:00
|
|
|
isc_rwlock_t *nlock = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
2024-03-12 11:32:29 -07:00
|
|
|
REQUIRE(version != NULL && version->qpdb == qpdb);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
|
|
|
if (type == dns_rdatatype_any) {
|
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
2025-08-11 07:17:43 +02:00
|
|
|
if (type == dns_rdatatype_rrsig && covers == dns_rdatatype_none) {
|
2023-11-19 00:00:49 -08:00
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
newheader = dns_slabheader_new(db->mctx, (dns_dbnode_t *)node);
|
2025-08-06 19:34:35 +02:00
|
|
|
newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
|
2025-02-03 14:06:37 +01:00
|
|
|
newheader->ttl = 0;
|
2023-11-19 00:00:49 -08:00
|
|
|
atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT);
|
2024-03-12 11:32:29 -07:00
|
|
|
newheader->serial = version->serial;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&node->name, nodename);
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-05-07 14:52:11 +02:00
|
|
|
nlock = qpzone_get_lock(node);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_WRLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
result = add(qpdb, node, nodename, version, newheader, DNS_DBADD_FORCE,
|
|
|
|
false, NULL, 0 DNS__DB_FLARG_PASS);
|
2025-01-27 21:07:11 +01:00
|
|
|
NODE_UNLOCK(nlock, &nlocktype);
|
2023-11-19 00:00:49 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-06 15:34:39 -08:00
|
|
|
static isc_result_t
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
nodefullname(dns_dbnode_t *node, dns_name_t *name) {
|
2024-03-06 15:34:39 -08:00
|
|
|
REQUIRE(node != NULL);
|
|
|
|
REQUIRE(name != NULL);
|
|
|
|
|
2025-07-02 18:19:50 +02:00
|
|
|
qpznode_t *qpnode = (qpznode_t *)node;
|
2025-01-27 21:07:11 +01:00
|
|
|
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_copy(&qpnode->name, name);
|
2025-01-27 21:07:11 +01:00
|
|
|
|
2024-03-06 15:34:39 -08:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static dns_glue_t *
|
2024-12-05 13:45:24 +01:00
|
|
|
new_glue(isc_mem_t *mctx, const dns_name_t *name) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
|
2024-12-05 13:45:24 +01:00
|
|
|
*glue = (dns_glue_t){
|
|
|
|
.name = DNS_NAME_INITEMPTY,
|
|
|
|
};
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_name_dup(name, mctx, &glue->name);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
return glue;
|
|
|
|
}
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
static dns_gluelist_t *
|
|
|
|
new_gluelist(dns_db_t *db, dns_slabheader_t *header,
|
|
|
|
const dns_dbversion_t *dbversion) {
|
|
|
|
dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist));
|
|
|
|
*gluelist = (dns_gluelist_t){
|
|
|
|
.version = dbversion,
|
|
|
|
.header = header,
|
|
|
|
};
|
|
|
|
|
|
|
|
isc_mem_attach(db->mctx, &gluelist->mctx);
|
|
|
|
|
|
|
|
cds_wfs_node_init(&gluelist->wfs_node);
|
|
|
|
|
|
|
|
return gluelist;
|
|
|
|
}
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
static isc_result_t
|
|
|
|
glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_rdataset_t *rdataset ISC_ATTR_UNUSED DNS__DB_FLARG) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
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;
|
2024-12-05 13:45:24 +01:00
|
|
|
const qpznode_t *node = NULL;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node_a = NULL;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
dns_fixedname_t fixedname_aaaa;
|
|
|
|
dns_name_t *name_aaaa = NULL;
|
|
|
|
dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node_aaaa = NULL;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
dns_glue_t *glue = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NS records want addresses in additional records.
|
|
|
|
*/
|
|
|
|
INSIST(qtype == dns_rdatatype_a);
|
|
|
|
|
|
|
|
ctx = (dns_glue_additionaldata_ctx_t *)arg;
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
node = (qpznode_t *)ctx->node;
|
|
|
|
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
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);
|
|
|
|
|
2024-11-14 11:18:00 +01:00
|
|
|
result = qpzone_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);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
if (result == DNS_R_GLUE) {
|
2024-12-05 13:45:24 +01:00
|
|
|
glue = new_glue(ctx->db->mctx, name_a);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-14 11:18:00 +01:00
|
|
|
result = qpzone_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);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
if (result == DNS_R_GLUE) {
|
|
|
|
if (glue == NULL) {
|
2024-12-05 13:45:24 +01:00
|
|
|
glue = new_glue(ctx->db->mctx, name_aaaa);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
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
|
2025-07-09 16:56:22 +02:00
|
|
|
* RRsets found for it with 'required' attribute. Note that for
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
* 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.
|
|
|
|
*/
|
2024-12-05 13:45:24 +01:00
|
|
|
if (glue != NULL && dns_name_issubdomain(name, &node->name)) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
if (dns_rdataset_isassociated(&glue->rdataset_a)) {
|
2025-07-09 16:56:22 +02:00
|
|
|
glue->rdataset_a.attributes.required = true;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
|
2025-07-09 16:56:22 +02:00
|
|
|
glue->rdataset_aaaa.attributes.required = true;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glue != NULL) {
|
2024-12-05 13:45:24 +01:00
|
|
|
glue->next = ctx->glue;
|
|
|
|
ctx->glue = glue;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
dns__db_detachnode((dns_dbnode_t **)&node_a DNS__DB_FLARG_PASS);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
if (node_aaaa != NULL) {
|
|
|
|
dns__db_detachnode(
|
2024-11-05 16:13:10 +01:00
|
|
|
(dns_dbnode_t **)&node_aaaa DNS__DB_FLARG_PASS);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-07-09 16:56:22 +02:00
|
|
|
#define IS_REQUIRED_GLUE(r) (((r)->attributes.required))
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
bool prepend_name = false;
|
|
|
|
|
|
|
|
dns_message_gettempname(msg, &name);
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_name_copy(&ge->name, name);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
static dns_gluelist_t *
|
|
|
|
create_gluelist(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
|
|
|
|
dns_rdataset_t *rdataset) {
|
2025-02-08 15:41:31 -08:00
|
|
|
dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
dns_glue_additionaldata_ctx_t ctx = {
|
2024-12-03 15:07:30 +01:00
|
|
|
.db = (dns_db_t *)qpdb,
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
.version = (dns_dbversion_t *)version,
|
2024-12-05 13:45:24 +01:00
|
|
|
.node = (dns_dbnode_t *)node,
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
};
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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).
|
|
|
|
*/
|
|
|
|
|
|
|
|
(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
|
2024-11-14 10:37:29 +01:00
|
|
|
glue_nsdname_cb, &ctx, 0);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-12-25 15:14:10 +01:00
|
|
|
CMM_STORE_SHARED(gluelist->glue, ctx.glue);
|
2024-12-05 13:45:24 +01:00
|
|
|
|
|
|
|
return gluelist;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
2024-07-04 10:07:18 +02:00
|
|
|
static void
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
|
|
|
|
dns_message_t *msg) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
2024-11-05 18:50:15 +01:00
|
|
|
qpz_version_t *version = (qpz_version_t *)dbversion;
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *node = (qpznode_t *)rdataset->slab.node;
|
2025-02-08 15:41:31 -08:00
|
|
|
dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_glue_t *glue = NULL;
|
|
|
|
isc_statscounter_t counter = dns_gluecachestatscounter_hits_absent;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
|
|
|
REQUIRE(rdataset->type == dns_rdatatype_ns);
|
|
|
|
REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db);
|
|
|
|
REQUIRE(qpdb == version->qpdb);
|
|
|
|
REQUIRE(!IS_STUB(qpdb));
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_gluelist_t *gluelist = rcu_dereference(header->gluelist);
|
|
|
|
if (gluelist == NULL || gluelist->version != dbversion) {
|
|
|
|
/* No or old glue list was found in the table. */
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
dns_gluelist_t *xchg_gluelist = gluelist;
|
|
|
|
dns_gluelist_t *old_gluelist = (void *)-1;
|
|
|
|
dns_gluelist_t *new_gluelist = create_gluelist(qpdb, version,
|
|
|
|
node, rdataset);
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-12-05 13:45:24 +01:00
|
|
|
while (old_gluelist != xchg_gluelist &&
|
|
|
|
(xchg_gluelist == NULL ||
|
|
|
|
xchg_gluelist->version != dbversion))
|
|
|
|
{
|
|
|
|
old_gluelist = xchg_gluelist;
|
|
|
|
xchg_gluelist = rcu_cmpxchg_pointer(
|
|
|
|
&header->gluelist, old_gluelist, new_gluelist);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_gluelist == xchg_gluelist) {
|
|
|
|
/* CAS was successful */
|
|
|
|
cds_wfs_push(&version->glue_stack,
|
|
|
|
&new_gluelist->wfs_node);
|
|
|
|
gluelist = new_gluelist;
|
|
|
|
} else {
|
|
|
|
destroy_gluelist(&new_gluelist);
|
|
|
|
gluelist = xchg_gluelist;
|
|
|
|
}
|
2024-12-03 15:07:30 +01:00
|
|
|
}
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
|
2024-12-25 15:14:10 +01:00
|
|
|
glue = CMM_LOAD_SHARED(gluelist->glue);
|
2024-12-05 13:45:24 +01:00
|
|
|
|
|
|
|
if (glue != NULL) {
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
addglue_to_message(glue, msg);
|
2024-12-05 13:45:24 +01:00
|
|
|
counter = dns_gluecachestatscounter_hits_present;
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
rcu_read_unlock();
|
2024-12-05 13:45:24 +01:00
|
|
|
|
|
|
|
/* We have a cached result. Add it to the message and return. */
|
|
|
|
if (qpdb->gluecachestats != NULL) {
|
|
|
|
isc_stats_increment(qpdb->gluecachestats, counter);
|
|
|
|
}
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
}
|
|
|
|
|
2024-03-01 08:26:07 +01:00
|
|
|
static void
|
|
|
|
setmaxrrperset(dns_db_t *db, uint32_t value) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
|
|
|
qpdb->maxrrperset = value;
|
|
|
|
}
|
|
|
|
|
2024-05-25 11:46:56 +02:00
|
|
|
static void
|
|
|
|
setmaxtypepername(dns_db_t *db, uint32_t value) {
|
|
|
|
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
|
|
|
|
|
|
|
REQUIRE(VALID_QPZONE(qpdb));
|
|
|
|
|
|
|
|
qpdb->maxtypepername = value;
|
|
|
|
}
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static dns_dbmethods_t qpdb_zonemethods = {
|
|
|
|
.destroy = qpdb_destroy,
|
|
|
|
.beginload = beginload,
|
|
|
|
.endload = endload,
|
|
|
|
.currentversion = currentversion,
|
2023-11-19 00:00:49 -08:00
|
|
|
.newversion = newversion,
|
2023-11-15 08:55:18 -08:00
|
|
|
.attachversion = attachversion,
|
2023-11-19 00:00:49 -08:00
|
|
|
.closeversion = closeversion,
|
2024-11-14 11:18:00 +01:00
|
|
|
.findnode = qpzone_findnode,
|
|
|
|
.find = qpzone_find,
|
|
|
|
.createiterator = qpzone_createiterator,
|
|
|
|
.findrdataset = qpzone_findrdataset,
|
|
|
|
.allrdatasets = qpzone_allrdatasets,
|
|
|
|
.addrdataset = qpzone_addrdataset,
|
|
|
|
.subtractrdataset = qpzone_subtractrdataset,
|
|
|
|
.deleterdataset = qpzone_deleterdataset,
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
.issecure = issecure,
|
|
|
|
.nodecount = nodecount,
|
2023-11-19 00:00:49 -08:00
|
|
|
.setloop = setloop,
|
|
|
|
.getoriginnode = getoriginnode,
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
.getnsec3parameters = getnsec3parameters,
|
2024-11-14 11:18:00 +01:00
|
|
|
.findnsec3node = qpzone_findnsec3node,
|
complete the qpzone database API implementation
finish importing the database API methods from RBTDB to qpzone:
issecure, nodecount, getnsec3parameters, findnsec3node, setsigningtime,
getsigningtime, getsize, setgluecachestats, locknode, unlocknode, and
addglue.
2023-11-28 13:31:15 -08:00
|
|
|
.setsigningtime = setsigningtime,
|
|
|
|
.getsigningtime = getsigningtime,
|
|
|
|
.getsize = getsize,
|
|
|
|
.setgluecachestats = setgluecachestats,
|
|
|
|
.addglue = addglue,
|
2024-03-01 08:26:07 +01:00
|
|
|
.setmaxrrperset = setmaxrrperset,
|
2024-05-25 11:46:56 +02:00
|
|
|
.setmaxtypepername = setmaxtypepername,
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
};
|
|
|
|
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
static dns_dbnode_methods_t qpznode_methods = (dns_dbnode_methods_t){
|
|
|
|
.nodefullname = nodefullname,
|
|
|
|
.attachnode = qpzone_attachnode,
|
|
|
|
.detachnode = qpzone_detachnode,
|
|
|
|
.locknode = locknode,
|
|
|
|
.unlocknode = unlocknode,
|
|
|
|
.deletedata = deletedata,
|
|
|
|
};
|
|
|
|
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
static void
|
2024-04-29 15:29:33 -07:00
|
|
|
destroy_qpznode(qpznode_t *node) {
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_t *top = NULL, *top_next = NULL;
|
|
|
|
dns_db_t *db = (dns_db_t *)node->qpdb;
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
for (top = node->data; top != NULL; top = top_next) {
|
|
|
|
top_next = top->next;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabheader_t *down = NULL, *down_next = NULL;
|
|
|
|
for (down = top->header; down != NULL; down = down_next) {
|
2023-11-19 00:00:49 -08:00
|
|
|
down_next = down->down;
|
|
|
|
dns_slabheader_destroy(&down);
|
|
|
|
}
|
2025-08-05 18:05:52 +02:00
|
|
|
top->header = NULL;
|
2023-11-19 00:00:49 -08:00
|
|
|
|
2025-08-05 18:05:52 +02:00
|
|
|
dns_slabtop_destroy(db->mctx, &top);
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
qpz_heap_unref(node->heap);
|
2024-03-11 18:47:01 -07:00
|
|
|
dns_name_free(&node->name, node->mctx);
|
2024-04-29 15:29:33 -07:00
|
|
|
isc_mem_putanddetach(&node->mctx, node, sizeof(qpznode_t));
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DNS_DB_NODETRACE
|
2024-03-12 01:05:07 -07:00
|
|
|
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpznode, destroy_qpznode);
|
2023-10-03 18:55:24 -07:00
|
|
|
#else
|
2024-03-12 01:05:07 -07:00
|
|
|
ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode);
|
2023-10-03 18:55:24 -07:00
|
|
|
#endif
|
|
|
|
|
2025-01-27 21:07:11 +01:00
|
|
|
#ifdef DNS_DB_NODETRACE
|
|
|
|
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpzonedb, qpzone_destroy);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_STATIC_IMPL(qpzonedb, qpzone_destroy);
|
|
|
|
#endif
|
|
|
|
|
2025-07-08 16:29:56 +02:00
|
|
|
ISC_REFCOUNT_STATIC_IMPL(qpz_heap, qpz_heap_destroy);
|
|
|
|
|
2023-10-03 18:55:24 -07:00
|
|
|
static void
|
|
|
|
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *data = pval;
|
|
|
|
qpznode_ref(data);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *data = pval;
|
|
|
|
qpznode_detach(&data);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
2024-04-29 15:29:33 -07:00
|
|
|
qpznode_t *data = pval;
|
2025-05-26 17:36:33 +02:00
|
|
|
return dns_qpkey_fromname(key, &data->name, data->nspace);
|
2023-10-03 18:55:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
make the qpzone database loadable
add database API methods needed for loading rdatasets into memory
(currentversion, beginload, endload), plus the methods used by
zone_postload() for zone consistency checks (getoriginnode, find,
findnode, findrdataset, attachnode, detachnode, deletedata).
the QP trie doesn't support the find callback mechanism available
in dns_rbt_findnode() which allows examination of intermediate nodes
while searching, so the detection of wildcard and delegation nodes
is now done by scanning QP chains after calling dns_qp_lookup().
Note that the lookup in previous_closest_nsec() cannot return
ISC_R_NOTFOUND. In RBTDB, we checked for this return value and
ovewrote the result with ISC_R_NOMORE if it occurred. In the
qpzone implementation, we insist that this return value cannot happen.
dns_qp_lookup() would only return ISC_R_NOTFOUND if we asked for a
name outside the zone's authoritative domain, and we never do that
when looking up a predecessor NSEC record.
named-checkzone is now able to load a zone and check it for errors,
but cannot dump it.
2023-11-04 15:40:49 +01:00
|
|
|
qp_triename(void *uctx ISC_ATTR_UNUSED, char *buf, size_t size) {
|
2023-10-03 18:55:24 -07:00
|
|
|
snprintf(buf, size, "QPDB");
|
|
|
|
}
|