1*bcda20f6Schristos /* $NetBSD: qpzone.c,v 1.2 2025/01/26 16:25:24 christos Exp $ */ 29689912eSchristos 39689912eSchristos /* 49689912eSchristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 59689912eSchristos * 69689912eSchristos * SPDX-License-Identifier: MPL-2.0 79689912eSchristos * 89689912eSchristos * This Source Code Form is subject to the terms of the Mozilla Public 99689912eSchristos * License, v. 2.0. If a copy of the MPL was not distributed with this 109689912eSchristos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 119689912eSchristos * 129689912eSchristos * See the COPYRIGHT file distributed with this work for additional 139689912eSchristos * information regarding copyright ownership. 149689912eSchristos */ 159689912eSchristos 169689912eSchristos /*! \file */ 179689912eSchristos 189689912eSchristos #include <inttypes.h> 199689912eSchristos #include <stdbool.h> 209689912eSchristos #include <sys/mman.h> 219689912eSchristos 229689912eSchristos #include <isc/ascii.h> 239689912eSchristos #include <isc/async.h> 249689912eSchristos #include <isc/atomic.h> 259689912eSchristos #include <isc/crc64.h> 269689912eSchristos #include <isc/file.h> 279689912eSchristos #include <isc/heap.h> 289689912eSchristos #include <isc/hex.h> 299689912eSchristos #include <isc/loop.h> 309689912eSchristos #include <isc/mem.h> 319689912eSchristos #include <isc/mutex.h> 329689912eSchristos #include <isc/once.h> 339689912eSchristos #include <isc/random.h> 349689912eSchristos #include <isc/refcount.h> 359689912eSchristos #include <isc/result.h> 369689912eSchristos #include <isc/rwlock.h> 379689912eSchristos #include <isc/serial.h> 389689912eSchristos #include <isc/stdio.h> 399689912eSchristos #include <isc/string.h> 409689912eSchristos #include <isc/time.h> 419689912eSchristos #include <isc/urcu.h> 429689912eSchristos #include <isc/util.h> 439689912eSchristos 449689912eSchristos #include <dns/callbacks.h> 459689912eSchristos #include <dns/db.h> 469689912eSchristos #include <dns/dbiterator.h> 479689912eSchristos #include <dns/fixedname.h> 489689912eSchristos #include <dns/log.h> 499689912eSchristos #include <dns/masterdump.h> 509689912eSchristos #include <dns/name.h> 519689912eSchristos #include <dns/nsec.h> 529689912eSchristos #include <dns/nsec3.h> 539689912eSchristos #include <dns/qp.h> 549689912eSchristos #include <dns/rdata.h> 559689912eSchristos #include <dns/rdataset.h> 569689912eSchristos #include <dns/rdatasetiter.h> 579689912eSchristos #include <dns/rdataslab.h> 589689912eSchristos #include <dns/rdatastruct.h> 599689912eSchristos #include <dns/stats.h> 609689912eSchristos #include <dns/time.h> 619689912eSchristos #include <dns/view.h> 629689912eSchristos #include <dns/zone.h> 639689912eSchristos #include <dns/zonekey.h> 649689912eSchristos 659689912eSchristos #include "db_p.h" 669689912eSchristos #include "qpzone_p.h" 679689912eSchristos 689689912eSchristos #define CHECK(op) \ 699689912eSchristos do { \ 709689912eSchristos result = (op); \ 719689912eSchristos if (result != ISC_R_SUCCESS) \ 729689912eSchristos goto failure; \ 739689912eSchristos } while (0) 749689912eSchristos 759689912eSchristos #define NONEXISTENT(header) \ 769689912eSchristos ((atomic_load_acquire(&(header)->attributes) & \ 779689912eSchristos DNS_SLABHEADERATTR_NONEXISTENT) != 0) 789689912eSchristos #define IGNORE(header) \ 799689912eSchristos ((atomic_load_acquire(&(header)->attributes) & \ 809689912eSchristos DNS_SLABHEADERATTR_IGNORE) != 0) 819689912eSchristos #define RESIGN(header) \ 829689912eSchristos ((atomic_load_acquire(&(header)->attributes) & \ 839689912eSchristos DNS_SLABHEADERATTR_RESIGN) != 0) 849689912eSchristos #define OPTOUT(header) \ 859689912eSchristos ((atomic_load_acquire(&(header)->attributes) & \ 869689912eSchristos DNS_SLABHEADERATTR_OPTOUT) != 0) 879689912eSchristos #define STATCOUNT(header) \ 889689912eSchristos ((atomic_load_acquire(&(header)->attributes) & \ 899689912eSchristos DNS_SLABHEADERATTR_STATCOUNT) != 0) 909689912eSchristos 919689912eSchristos #define HEADERNODE(h) ((qpznode_t *)((h)->node)) 929689912eSchristos 939689912eSchristos #define QPDB_ATTR_LOADED 0x01 949689912eSchristos #define QPDB_ATTR_LOADING 0x02 959689912eSchristos 969689912eSchristos #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ 979689912eSchristos 989689912eSchristos #define QPDBITER_NSEC3_ORIGIN_NODE(qpdb, iterator) \ 999689912eSchristos ((iterator)->current == &(iterator)->nsec3iter && \ 1009689912eSchristos (iterator)->node == (qpdb)->nsec3_origin) 1019689912eSchristos 1029689912eSchristos /*% 1039689912eSchristos * Note that "impmagic" is not the first four bytes of the struct, so 1049689912eSchristos * ISC_MAGIC_VALID cannot be used. 1059689912eSchristos */ 1069689912eSchristos #define QPZONE_DB_MAGIC ISC_MAGIC('Q', 'Z', 'D', 'B') 1079689912eSchristos #define VALID_QPZONE(qpdb) \ 1089689912eSchristos ((qpdb) != NULL && (qpdb)->common.impmagic == QPZONE_DB_MAGIC) 1099689912eSchristos 1109689912eSchristos typedef struct qpzonedb qpzonedb_t; 1119689912eSchristos typedef struct qpznode qpznode_t; 1129689912eSchristos 1139689912eSchristos typedef struct qpz_changed { 1149689912eSchristos qpznode_t *node; 1159689912eSchristos bool dirty; 1169689912eSchristos ISC_LINK(struct qpz_changed) link; 1179689912eSchristos } qpz_changed_t; 1189689912eSchristos 1199689912eSchristos typedef ISC_LIST(qpz_changed_t) qpz_changedlist_t; 1209689912eSchristos 1219689912eSchristos typedef struct qpz_version qpz_version_t; 1229689912eSchristos struct qpz_version { 1239689912eSchristos /* Not locked */ 1249689912eSchristos uint32_t serial; 1259689912eSchristos qpzonedb_t *qpdb; 1269689912eSchristos isc_refcount_t references; 1279689912eSchristos /* Locked by database lock. */ 1289689912eSchristos bool writer; 1299689912eSchristos qpz_changedlist_t changed_list; 1309689912eSchristos dns_slabheaderlist_t resigned_list; 1319689912eSchristos ISC_LINK(qpz_version_t) link; 1329689912eSchristos bool secure; 1339689912eSchristos bool havensec3; 1349689912eSchristos /* NSEC3 parameters */ 1359689912eSchristos dns_hash_t hash; 1369689912eSchristos uint8_t flags; 1379689912eSchristos uint16_t iterations; 1389689912eSchristos uint8_t salt_length; 1399689912eSchristos unsigned char salt[DNS_NSEC3_SALTSIZE]; 1409689912eSchristos 1419689912eSchristos /* 1429689912eSchristos * records and xfrsize are covered by rwlock. 1439689912eSchristos */ 1449689912eSchristos isc_rwlock_t rwlock; 1459689912eSchristos uint64_t records; 1469689912eSchristos uint64_t xfrsize; 1479689912eSchristos 1489689912eSchristos struct cds_lfht *glue_table; 1499689912eSchristos }; 1509689912eSchristos 1519689912eSchristos typedef ISC_LIST(qpz_version_t) qpz_versionlist_t; 1529689912eSchristos 1539689912eSchristos struct qpznode { 1549689912eSchristos dns_name_t name; 1559689912eSchristos isc_mem_t *mctx; 1569689912eSchristos isc_refcount_t references; 1579689912eSchristos isc_refcount_t erefs; 1589689912eSchristos uint16_t locknum; 1599689912eSchristos void *data; 1609689912eSchristos atomic_uint_fast8_t nsec; 1619689912eSchristos atomic_bool wild; 1629689912eSchristos atomic_bool delegating; 1639689912eSchristos atomic_bool dirty; 1649689912eSchristos }; 1659689912eSchristos 1669689912eSchristos struct qpzonedb { 1679689912eSchristos /* Unlocked. */ 1689689912eSchristos dns_db_t common; 1699689912eSchristos /* Locks the data in this struct */ 1709689912eSchristos isc_rwlock_t lock; 1719689912eSchristos /* Locks for tree nodes */ 1729689912eSchristos int node_lock_count; 1739689912eSchristos db_nodelock_t *node_locks; 1749689912eSchristos qpznode_t *origin; 1759689912eSchristos qpznode_t *nsec3_origin; 1769689912eSchristos isc_stats_t *gluecachestats; 1779689912eSchristos /* Locked by lock. */ 1789689912eSchristos unsigned int active; 1799689912eSchristos unsigned int attributes; 1809689912eSchristos uint32_t current_serial; 1819689912eSchristos uint32_t least_serial; 1829689912eSchristos uint32_t next_serial; 1839689912eSchristos uint32_t maxrrperset; /* Maximum RRs per RRset */ 1849689912eSchristos uint32_t maxtypepername; /* Maximum number of RR types per owner */ 1859689912eSchristos qpz_version_t *current_version; 1869689912eSchristos qpz_version_t *future_version; 1879689912eSchristos qpz_versionlist_t open_versions; 1889689912eSchristos isc_loop_t *loop; 1899689912eSchristos struct rcu_head rcu_head; 1909689912eSchristos 1919689912eSchristos isc_heap_t *heap; /* Resigning heap */ 1929689912eSchristos 1939689912eSchristos dns_qpmulti_t *tree; /* Main QP trie for data storage */ 1949689912eSchristos dns_qpmulti_t *nsec; /* NSEC nodes only */ 1959689912eSchristos dns_qpmulti_t *nsec3; /* NSEC3 nodes only */ 1969689912eSchristos }; 1979689912eSchristos 1989689912eSchristos /*% 1999689912eSchristos * Search Context 2009689912eSchristos */ 2019689912eSchristos typedef struct { 2029689912eSchristos qpzonedb_t *qpdb; 2039689912eSchristos qpz_version_t *version; 2049689912eSchristos dns_qpread_t qpr; 2059689912eSchristos uint32_t serial; 2069689912eSchristos unsigned int options; 2079689912eSchristos dns_qpchain_t chain; 2089689912eSchristos dns_qpiter_t iter; 2099689912eSchristos bool copy_name; 2109689912eSchristos bool need_cleanup; 2119689912eSchristos bool wild; 2129689912eSchristos qpznode_t *zonecut; 2139689912eSchristos dns_slabheader_t *zonecut_header; 2149689912eSchristos dns_slabheader_t *zonecut_sigheader; 2159689912eSchristos dns_fixedname_t zonecut_name; 2169689912eSchristos isc_stdtime_t now; 2179689912eSchristos } qpz_search_t; 2189689912eSchristos 2199689912eSchristos typedef struct dns_gluenode_t { 2209689912eSchristos isc_mem_t *mctx; 2219689912eSchristos 2229689912eSchristos struct dns_glue *glue; 2239689912eSchristos 2249689912eSchristos qpznode_t *node; 2259689912eSchristos 2269689912eSchristos struct cds_lfht_node ht_node; 2279689912eSchristos struct rcu_head rcu_head; 2289689912eSchristos } dns_gluenode_t; 2299689912eSchristos 2309689912eSchristos /*% 2319689912eSchristos * Load Context 2329689912eSchristos */ 2339689912eSchristos typedef struct { 2349689912eSchristos dns_db_t *db; 2359689912eSchristos isc_stdtime_t now; 2369689912eSchristos dns_qp_t *tree; 2379689912eSchristos dns_qp_t *nsec; 2389689912eSchristos dns_qp_t *nsec3; 2399689912eSchristos } qpz_load_t; 2409689912eSchristos 2419689912eSchristos static dns_dbmethods_t qpdb_zonemethods; 2429689912eSchristos 2439689912eSchristos #if DNS_DB_NODETRACE 2449689912eSchristos #define qpznode_ref(ptr) qpznode__ref(ptr, __func__, __FILE__, __LINE__) 2459689912eSchristos #define qpznode_unref(ptr) qpznode__unref(ptr, __func__, __FILE__, __LINE__) 2469689912eSchristos #define qpznode_attach(ptr, ptrp) \ 2479689912eSchristos qpznode__attach(ptr, ptrp, __func__, __FILE__, __LINE__) 2489689912eSchristos #define qpznode_detach(ptrp) qpznode__detach(ptrp, __func__, __FILE__, __LINE__) 2499689912eSchristos ISC_REFCOUNT_STATIC_TRACE_DECL(qpznode); 2509689912eSchristos #else 2519689912eSchristos ISC_REFCOUNT_STATIC_DECL(qpznode); 2529689912eSchristos #endif 2539689912eSchristos 2549689912eSchristos /* QP trie methods */ 2559689912eSchristos static void 2569689912eSchristos qp_attach(void *uctx, void *pval, uint32_t ival); 2579689912eSchristos static void 2589689912eSchristos qp_detach(void *uctx, void *pval, uint32_t ival); 2599689912eSchristos static size_t 2609689912eSchristos qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival); 2619689912eSchristos static void 2629689912eSchristos qp_triename(void *uctx, char *buf, size_t size); 2639689912eSchristos 2649689912eSchristos static dns_qpmethods_t qpmethods = { 2659689912eSchristos qp_attach, 2669689912eSchristos qp_detach, 2679689912eSchristos qp_makekey, 2689689912eSchristos qp_triename, 2699689912eSchristos }; 2709689912eSchristos 2719689912eSchristos static void 2729689912eSchristos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG); 2739689912eSchristos static isc_result_t 2749689912eSchristos rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG); 2759689912eSchristos static isc_result_t 2769689912eSchristos rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG); 2779689912eSchristos static void 2789689912eSchristos rdatasetiter_current(dns_rdatasetiter_t *iterator, 2799689912eSchristos dns_rdataset_t *rdataset DNS__DB_FLARG); 2809689912eSchristos 2819689912eSchristos static dns_rdatasetitermethods_t rdatasetiter_methods = { 2829689912eSchristos rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next, 2839689912eSchristos rdatasetiter_current 2849689912eSchristos }; 2859689912eSchristos 2869689912eSchristos typedef struct qpdb_rdatasetiter { 2879689912eSchristos dns_rdatasetiter_t common; 2889689912eSchristos dns_slabheader_t *current; 2899689912eSchristos } qpdb_rdatasetiter_t; 2909689912eSchristos 2919689912eSchristos /* 2929689912eSchristos * Note that these iterators, unless created with either DNS_DB_NSEC3ONLY 2939689912eSchristos * or DNS_DB_NONSEC3, will transparently move between the last node of the 2949689912eSchristos * "regular" QP trie and the root node of the NSEC3 QP trie of the database 2959689912eSchristos * in question, as if the latter was a successor to the former in lexical 2969689912eSchristos * order. The "current" field always holds the address of either 2979689912eSchristos * "mainiter" or "nsec3iter", depending on which trie is being traversed 2989689912eSchristos * at given time. 2999689912eSchristos */ 3009689912eSchristos static void 3019689912eSchristos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG); 3029689912eSchristos static isc_result_t 3039689912eSchristos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG); 3049689912eSchristos static isc_result_t 3059689912eSchristos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG); 3069689912eSchristos static isc_result_t 3079689912eSchristos dbiterator_seek(dns_dbiterator_t *iterator, 3089689912eSchristos const dns_name_t *name DNS__DB_FLARG); 3099689912eSchristos static isc_result_t 3109689912eSchristos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG); 3119689912eSchristos static isc_result_t 3129689912eSchristos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG); 3139689912eSchristos static isc_result_t 3149689912eSchristos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, 3159689912eSchristos dns_name_t *name DNS__DB_FLARG); 3169689912eSchristos static isc_result_t 3179689912eSchristos dbiterator_pause(dns_dbiterator_t *iterator); 3189689912eSchristos static isc_result_t 3199689912eSchristos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name); 3209689912eSchristos 3219689912eSchristos static dns_dbiteratormethods_t dbiterator_methods = { 3229689912eSchristos dbiterator_destroy, dbiterator_first, dbiterator_last, 3239689912eSchristos dbiterator_seek, dbiterator_prev, dbiterator_next, 3249689912eSchristos dbiterator_current, dbiterator_pause, dbiterator_origin 3259689912eSchristos }; 3269689912eSchristos 3279689912eSchristos typedef struct qpdb_dbiterator { 3289689912eSchristos dns_dbiterator_t common; 3299689912eSchristos isc_result_t result; 3309689912eSchristos dns_qpsnap_t *tsnap; /* main tree snapshot */ 3319689912eSchristos dns_qpsnap_t *nsnap; /* nsec3 tree snapshot */ 3329689912eSchristos dns_qpiter_t *current; /* current iterator, which is one of: */ 3339689912eSchristos dns_qpiter_t mainiter; /* - main tree iterator */ 3349689912eSchristos dns_qpiter_t nsec3iter; /* - nsec3 tree iterator */ 3359689912eSchristos qpznode_t *node; 3369689912eSchristos enum { full, nonsec3, nsec3only } nsec3mode; 3379689912eSchristos } qpdb_dbiterator_t; 3389689912eSchristos 3399689912eSchristos /*% 3409689912eSchristos * 'init_count' is used to initialize 'newheader->count' which inturn 3419689912eSchristos * is used to determine where in the cycle rrset-order cyclic starts. 3429689912eSchristos * We don't lock this as we don't care about simultaneous updates. 3439689912eSchristos */ 3449689912eSchristos static atomic_uint_fast16_t init_count = 0; 3459689912eSchristos 3469689912eSchristos /* 3479689912eSchristos * Locking 3489689912eSchristos * 3499689912eSchristos * If a routine is going to lock more than one lock in this module, then 3509689912eSchristos * the locking must be done in the following order: 3519689912eSchristos * 3529689912eSchristos * Node Lock (Only one from the set may be locked at one time by 3539689912eSchristos * any caller) 3549689912eSchristos * 3559689912eSchristos * Database Lock 3569689912eSchristos * 3579689912eSchristos * Failure to follow this hierarchy can result in deadlock. 3589689912eSchristos */ 3599689912eSchristos 3609689912eSchristos /*% 3619689912eSchristos * Return which RRset should be resigned sooner. If the RRsets have the 3629689912eSchristos * same signing time, prefer the other RRset over the SOA RRset. 3639689912eSchristos */ 3649689912eSchristos static bool 3659689912eSchristos resign_sooner(void *v1, void *v2) { 3669689912eSchristos dns_slabheader_t *h1 = v1; 3679689912eSchristos dns_slabheader_t *h2 = v2; 3689689912eSchristos 3699689912eSchristos return h1->resign < h2->resign || 3709689912eSchristos (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) || 3719689912eSchristos (h1->resign == h2->resign && h1->resign_lsb == h2->resign_lsb && 3729689912eSchristos h2->type == DNS_SIGTYPE(dns_rdatatype_soa)); 3739689912eSchristos } 3749689912eSchristos 3759689912eSchristos /*% 3769689912eSchristos * This function sets the heap index into the header. 3779689912eSchristos */ 3789689912eSchristos static void 3799689912eSchristos set_index(void *what, unsigned int idx) { 3809689912eSchristos dns_slabheader_t *h = what; 3819689912eSchristos 3829689912eSchristos h->heap_index = idx; 3839689912eSchristos } 3849689912eSchristos 3859689912eSchristos static void 3869689912eSchristos free_gluenode(dns_gluenode_t *gluenode); 3879689912eSchristos 3889689912eSchristos static void 3899689912eSchristos free_gluetable(struct cds_lfht *glue_table) { 3909689912eSchristos struct cds_lfht_iter iter; 3919689912eSchristos dns_gluenode_t *gluenode = NULL; 3929689912eSchristos 3939689912eSchristos rcu_read_lock(); 3949689912eSchristos cds_lfht_for_each_entry(glue_table, &iter, gluenode, ht_node) { 3959689912eSchristos INSIST(!cds_lfht_del(glue_table, &gluenode->ht_node)); 3969689912eSchristos free_gluenode(gluenode); 3979689912eSchristos } 3989689912eSchristos rcu_read_unlock(); 3999689912eSchristos 4009689912eSchristos cds_lfht_destroy(glue_table, NULL); 4019689912eSchristos } 4029689912eSchristos 4039689912eSchristos static void 4049689912eSchristos free_db_rcu(struct rcu_head *rcu_head) { 4059689912eSchristos qpzonedb_t *qpdb = caa_container_of(rcu_head, qpzonedb_t, rcu_head); 4069689912eSchristos 4079689912eSchristos if (dns_name_dynamic(&qpdb->common.origin)) { 4089689912eSchristos dns_name_free(&qpdb->common.origin, qpdb->common.mctx); 4099689912eSchristos } 4109689912eSchristos for (int i = 0; i < qpdb->node_lock_count; i++) { 4119689912eSchristos isc_refcount_destroy(&qpdb->node_locks[i].references); 4129689912eSchristos NODE_DESTROYLOCK(&qpdb->node_locks[i].lock); 4139689912eSchristos } 4149689912eSchristos 4159689912eSchristos isc_heap_destroy(&qpdb->heap); 4169689912eSchristos 4179689912eSchristos if (qpdb->gluecachestats != NULL) { 4189689912eSchristos isc_stats_detach(&qpdb->gluecachestats); 4199689912eSchristos } 4209689912eSchristos 4219689912eSchristos isc_mem_cput(qpdb->common.mctx, qpdb->node_locks, qpdb->node_lock_count, 4229689912eSchristos sizeof(db_nodelock_t)); 4239689912eSchristos isc_refcount_destroy(&qpdb->common.references); 4249689912eSchristos if (qpdb->loop != NULL) { 4259689912eSchristos isc_loop_detach(&qpdb->loop); 4269689912eSchristos } 4279689912eSchristos 4289689912eSchristos isc_rwlock_destroy(&qpdb->lock); 4299689912eSchristos qpdb->common.magic = 0; 4309689912eSchristos qpdb->common.impmagic = 0; 4319689912eSchristos 4329689912eSchristos if (qpdb->common.update_listeners != NULL) { 4339689912eSchristos INSIST(!cds_lfht_destroy(qpdb->common.update_listeners, NULL)); 4349689912eSchristos } 4359689912eSchristos 4369689912eSchristos isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb)); 4379689912eSchristos } 4389689912eSchristos 4399689912eSchristos static void 4409689912eSchristos free_qpdb(qpzonedb_t *qpdb, bool log) { 4419689912eSchristos REQUIRE(qpdb->future_version == NULL); 4429689912eSchristos 4439689912eSchristos isc_refcount_decrementz(&qpdb->current_version->references); 4449689912eSchristos 4459689912eSchristos isc_refcount_destroy(&qpdb->current_version->references); 4469689912eSchristos UNLINK(qpdb->open_versions, qpdb->current_version, link); 4479689912eSchristos isc_rwlock_destroy(&qpdb->current_version->rwlock); 4489689912eSchristos isc_mem_put(qpdb->common.mctx, qpdb->current_version, 4499689912eSchristos sizeof(*qpdb->current_version)); 4509689912eSchristos 4519689912eSchristos dns_qpmulti_destroy(&qpdb->tree); 4529689912eSchristos dns_qpmulti_destroy(&qpdb->nsec); 4539689912eSchristos dns_qpmulti_destroy(&qpdb->nsec3); 4549689912eSchristos 4559689912eSchristos if (log) { 4569689912eSchristos char buf[DNS_NAME_FORMATSIZE]; 4579689912eSchristos if (dns_name_dynamic(&qpdb->common.origin)) { 4589689912eSchristos dns_name_format(&qpdb->common.origin, buf, sizeof(buf)); 4599689912eSchristos } else { 4609689912eSchristos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 4619689912eSchristos } 4629689912eSchristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 4639689912eSchristos DNS_LOGMODULE_DB, ISC_LOG_DEBUG(1), 4649689912eSchristos "called free_qpdb(%s)", buf); 4659689912eSchristos } 4669689912eSchristos 4679689912eSchristos call_rcu(&qpdb->rcu_head, free_db_rcu); 4689689912eSchristos } 4699689912eSchristos 4709689912eSchristos static void 4719689912eSchristos qpdb_destroy(dns_db_t *arg) { 4729689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)arg; 4739689912eSchristos unsigned int inactive = 0; 4749689912eSchristos 4759689912eSchristos if (qpdb->origin != NULL) { 4769689912eSchristos qpznode_detach(&qpdb->origin); 4779689912eSchristos } 4789689912eSchristos if (qpdb->nsec3_origin != NULL) { 4799689912eSchristos qpznode_detach(&qpdb->nsec3_origin); 4809689912eSchristos } 4819689912eSchristos 4829689912eSchristos /* 4839689912eSchristos * The current version's glue table needs to be freed early 4849689912eSchristos * so the nodes are dereferenced before we check the active 4859689912eSchristos * node count below. 4869689912eSchristos */ 4879689912eSchristos if (qpdb->current_version != NULL) { 4889689912eSchristos free_gluetable(qpdb->current_version->glue_table); 4899689912eSchristos } 4909689912eSchristos 4919689912eSchristos /* 4929689912eSchristos * Even though there are no external direct references, there still 4939689912eSchristos * may be nodes in use. 4949689912eSchristos */ 4959689912eSchristos for (int i = 0; i < qpdb->node_lock_count; i++) { 4969689912eSchristos isc_rwlocktype_t nodelock = isc_rwlocktype_none; 4979689912eSchristos NODE_WRLOCK(&qpdb->node_locks[i].lock, &nodelock); 4989689912eSchristos qpdb->node_locks[i].exiting = true; 4999689912eSchristos if (isc_refcount_current(&qpdb->node_locks[i].references) == 0) 5009689912eSchristos { 5019689912eSchristos inactive++; 5029689912eSchristos } 5039689912eSchristos NODE_UNLOCK(&qpdb->node_locks[i].lock, &nodelock); 5049689912eSchristos } 5059689912eSchristos 5069689912eSchristos if (inactive != 0) { 5079689912eSchristos bool want_free = false; 5089689912eSchristos 5099689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 5109689912eSchristos qpdb->active -= inactive; 5119689912eSchristos if (qpdb->active == 0) { 5129689912eSchristos want_free = true; 5139689912eSchristos } 5149689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 5159689912eSchristos 5169689912eSchristos if (want_free) { 5179689912eSchristos char buf[DNS_NAME_FORMATSIZE]; 5189689912eSchristos if (dns_name_dynamic(&qpdb->common.origin)) { 5199689912eSchristos dns_name_format(&qpdb->common.origin, buf, 5209689912eSchristos sizeof(buf)); 5219689912eSchristos } else { 5229689912eSchristos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 5239689912eSchristos } 5249689912eSchristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 5259689912eSchristos DNS_LOGMODULE_DB, ISC_LOG_DEBUG(1), 5269689912eSchristos "calling free_qpdb(%s)", buf); 5279689912eSchristos free_qpdb(qpdb, true); 5289689912eSchristos } 5299689912eSchristos } 5309689912eSchristos } 5319689912eSchristos 5329689912eSchristos static qpznode_t * 5339689912eSchristos new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name) { 5349689912eSchristos qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata)); 5359689912eSchristos *newdata = (qpznode_t){ 5369689912eSchristos .name = DNS_NAME_INITEMPTY, 5379689912eSchristos .references = ISC_REFCOUNT_INITIALIZER(1), 5389689912eSchristos }; 5399689912eSchristos newdata->locknum = dns_name_hash(name) % qpdb->node_lock_count; 5409689912eSchristos dns_name_dupwithoffsets(name, qpdb->common.mctx, &newdata->name); 5419689912eSchristos isc_mem_attach(qpdb->common.mctx, &newdata->mctx); 5429689912eSchristos 5439689912eSchristos #if DNS_DB_NODETRACE 5449689912eSchristos fprintf(stderr, "new_qpznode:%s:%s:%d:%p->references = 1\n", __func__, 5459689912eSchristos __FILE__, __LINE__ + 1, name); 5469689912eSchristos #endif 5479689912eSchristos return newdata; 5489689912eSchristos } 5499689912eSchristos 5509689912eSchristos static qpz_version_t * 5519689912eSchristos allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references, 5529689912eSchristos bool writer) { 5539689912eSchristos qpz_version_t *version = isc_mem_get(mctx, sizeof(*version)); 5549689912eSchristos *version = (qpz_version_t){ 5559689912eSchristos .serial = serial, 5569689912eSchristos .writer = writer, 5579689912eSchristos .changed_list = ISC_LIST_INITIALIZER, 5589689912eSchristos .resigned_list = ISC_LIST_INITIALIZER, 5599689912eSchristos .link = ISC_LINK_INITIALIZER, 5609689912eSchristos .glue_table = cds_lfht_new(GLUETABLE_INIT_SIZE, 5619689912eSchristos GLUETABLE_MIN_SIZE, 0, 5629689912eSchristos CDS_LFHT_AUTO_RESIZE, NULL), 5639689912eSchristos }; 5649689912eSchristos 5659689912eSchristos isc_rwlock_init(&version->rwlock); 5669689912eSchristos isc_refcount_init(&version->references, references); 5679689912eSchristos 5689689912eSchristos return version; 5699689912eSchristos } 5709689912eSchristos 5719689912eSchristos isc_result_t 5729689912eSchristos dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, 5739689912eSchristos dns_rdataclass_t rdclass, unsigned int argc ISC_ATTR_UNUSED, 5749689912eSchristos char **argv ISC_ATTR_UNUSED, void *driverarg ISC_ATTR_UNUSED, 5759689912eSchristos dns_db_t **dbp) { 5769689912eSchristos qpzonedb_t *qpdb = NULL; 5779689912eSchristos isc_result_t result; 5789689912eSchristos dns_qp_t *qp = NULL; 5799689912eSchristos 5809689912eSchristos qpdb = isc_mem_get(mctx, sizeof(*qpdb)); 5819689912eSchristos *qpdb = (qpzonedb_t){ 5829689912eSchristos .common.origin = DNS_NAME_INITEMPTY, 5839689912eSchristos .common.rdclass = rdclass, 5849689912eSchristos .node_lock_count = DEFAULT_NODE_LOCK_COUNT, 5859689912eSchristos .current_serial = 1, 5869689912eSchristos .least_serial = 1, 5879689912eSchristos .next_serial = 2, 5889689912eSchristos .open_versions = ISC_LIST_INITIALIZER, 5899689912eSchristos }; 5909689912eSchristos 5919689912eSchristos isc_refcount_init(&qpdb->common.references, 1); 5929689912eSchristos 5939689912eSchristos qpdb->common.methods = &qpdb_zonemethods; 5949689912eSchristos if (type == dns_dbtype_stub) { 5959689912eSchristos qpdb->common.attributes |= DNS_DBATTR_STUB; 5969689912eSchristos } 5979689912eSchristos 5989689912eSchristos isc_rwlock_init(&qpdb->lock); 5999689912eSchristos 6009689912eSchristos qpdb->node_locks = isc_mem_cget(mctx, qpdb->node_lock_count, 6019689912eSchristos sizeof(db_nodelock_t)); 6029689912eSchristos 6039689912eSchristos qpdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL); 6049689912eSchristos 6059689912eSchristos isc_heap_create(mctx, resign_sooner, set_index, 0, &qpdb->heap); 6069689912eSchristos 6079689912eSchristos qpdb->active = qpdb->node_lock_count; 6089689912eSchristos 6099689912eSchristos for (int i = 0; i < qpdb->node_lock_count; i++) { 6109689912eSchristos NODE_INITLOCK(&qpdb->node_locks[i].lock); 6119689912eSchristos isc_refcount_init(&qpdb->node_locks[i].references, 0); 6129689912eSchristos qpdb->node_locks[i].exiting = false; 6139689912eSchristos } 6149689912eSchristos 6159689912eSchristos /* 6169689912eSchristos * Attach to the mctx. The database will persist so long as there 6179689912eSchristos * are references to it, and attaching to the mctx ensures that our 6189689912eSchristos * mctx won't disappear out from under us. 6199689912eSchristos */ 6209689912eSchristos isc_mem_attach(mctx, &qpdb->common.mctx); 6219689912eSchristos 6229689912eSchristos /* 6239689912eSchristos * Make a copy of the origin name. 6249689912eSchristos */ 6259689912eSchristos dns_name_dupwithoffsets(origin, mctx, &qpdb->common.origin); 6269689912eSchristos 6279689912eSchristos dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->tree); 6289689912eSchristos dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec); 6299689912eSchristos dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec3); 6309689912eSchristos 6319689912eSchristos /* 6329689912eSchristos * Version initialization. 6339689912eSchristos */ 6349689912eSchristos qpdb->current_version = allocate_version(mctx, 1, 1, false); 6359689912eSchristos qpdb->current_version->qpdb = qpdb; 6369689912eSchristos 6379689912eSchristos /* 6389689912eSchristos * In order to set the node callback bit correctly in zone databases, 6399689912eSchristos * we need to know if the node has the origin name of the zone. 6409689912eSchristos * In loading_addrdataset() we could simply compare the new name 6419689912eSchristos * to the origin name, but this is expensive. Also, we don't know the 6429689912eSchristos * node name in addrdataset(), so we need another way of knowing the 6439689912eSchristos * zone's top. 6449689912eSchristos * 6459689912eSchristos * We now explicitly create a node for the zone's origin, and then 6469689912eSchristos * we simply remember the node data's address. 6479689912eSchristos */ 6489689912eSchristos 6499689912eSchristos dns_qpmulti_write(qpdb->tree, &qp); 6509689912eSchristos qpdb->origin = new_qpznode(qpdb, &qpdb->common.origin); 6519689912eSchristos result = dns_qp_insert(qp, qpdb->origin, 0); 6529689912eSchristos qpdb->origin->nsec = DNS_DB_NSEC_NORMAL; 6539689912eSchristos dns_qpmulti_commit(qpdb->tree, &qp); 6549689912eSchristos 6559689912eSchristos if (result != ISC_R_SUCCESS) { 6569689912eSchristos INSIST(result != ISC_R_EXISTS); 6579689912eSchristos free_qpdb(qpdb, false); 6589689912eSchristos return result; 6599689912eSchristos } 6609689912eSchristos 6619689912eSchristos /* 6629689912eSchristos * Add an apex node to the NSEC3 tree so that NSEC3 searches 6639689912eSchristos * return partial matches when there is only a single NSEC3 6649689912eSchristos * record in the tree. 6659689912eSchristos */ 6669689912eSchristos dns_qpmulti_write(qpdb->nsec3, &qp); 6679689912eSchristos qpdb->nsec3_origin = new_qpznode(qpdb, &qpdb->common.origin); 6689689912eSchristos qpdb->nsec3_origin->nsec = DNS_DB_NSEC_NSEC3; 6699689912eSchristos result = dns_qp_insert(qp, qpdb->nsec3_origin, 0); 6709689912eSchristos dns_qpmulti_commit(qpdb->nsec3, &qp); 6719689912eSchristos 6729689912eSchristos if (result != ISC_R_SUCCESS) { 6739689912eSchristos INSIST(result != ISC_R_EXISTS); 6749689912eSchristos free_qpdb(qpdb, false); 6759689912eSchristos return result; 6769689912eSchristos } 6779689912eSchristos 6789689912eSchristos /* 6799689912eSchristos * Keep the current version in the open list so that list operation 6809689912eSchristos * won't happen in normal lookup operations. 6819689912eSchristos */ 6829689912eSchristos PREPEND(qpdb->open_versions, qpdb->current_version, link); 6839689912eSchristos 6849689912eSchristos qpdb->common.magic = DNS_DB_MAGIC; 6859689912eSchristos qpdb->common.impmagic = QPZONE_DB_MAGIC; 6869689912eSchristos 6879689912eSchristos *dbp = (dns_db_t *)qpdb; 6889689912eSchristos 6899689912eSchristos return ISC_R_SUCCESS; 6909689912eSchristos } 6919689912eSchristos 6929689912eSchristos static void 6939689912eSchristos newref(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) { 6949689912eSchristos uint_fast32_t refs; 6959689912eSchristos 6969689912eSchristos qpznode_ref(node); 6979689912eSchristos refs = isc_refcount_increment0(&node->erefs); 6989689912eSchristos #if DNS_DB_NODETRACE 6999689912eSchristos fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n", 7009689912eSchristos func, file, line, node, refs + 1); 7019689912eSchristos #else 7029689912eSchristos UNUSED(refs); 7039689912eSchristos #endif 7049689912eSchristos 7059689912eSchristos if (refs == 0) { 7069689912eSchristos /* this is the first reference to the node */ 7079689912eSchristos refs = isc_refcount_increment0( 7089689912eSchristos &qpdb->node_locks[node->locknum].references); 7099689912eSchristos #if DNS_DB_NODETRACE 7109689912eSchristos fprintf(stderr, 7119689912eSchristos "incr:nodelock:%s:%s:%u:%p:%p->references = " 7129689912eSchristos "%" PRIuFAST32 "\n", 7139689912eSchristos func, file, line, node, 7149689912eSchristos &qpdb->node_locks[node->locknum], refs + 1); 7159689912eSchristos #else 7169689912eSchristos UNUSED(refs); 7179689912eSchristos #endif 7189689912eSchristos } 7199689912eSchristos } 7209689912eSchristos 7219689912eSchristos static void 7229689912eSchristos clean_zone_node(qpznode_t *node, uint32_t least_serial) { 7239689912eSchristos dns_slabheader_t *current = NULL, *dcurrent = NULL; 7249689912eSchristos dns_slabheader_t *down_next = NULL, *dparent = NULL; 7259689912eSchristos dns_slabheader_t *top_prev = NULL, *top_next = NULL; 7269689912eSchristos bool still_dirty = false; 7279689912eSchristos 7289689912eSchristos /* 7299689912eSchristos * Caller must be holding the node lock. 7309689912eSchristos */ 7319689912eSchristos REQUIRE(least_serial != 0); 7329689912eSchristos 7339689912eSchristos for (current = node->data; current != NULL; current = top_next) { 7349689912eSchristos top_next = current->next; 7359689912eSchristos 7369689912eSchristos /* 7379689912eSchristos * First, we clean up any instances of multiple rdatasets 7389689912eSchristos * with the same serial number, or that have the IGNORE 7399689912eSchristos * attribute. 7409689912eSchristos */ 7419689912eSchristos dparent = current; 7429689912eSchristos for (dcurrent = current->down; dcurrent != NULL; 7439689912eSchristos dcurrent = down_next) 7449689912eSchristos { 7459689912eSchristos down_next = dcurrent->down; 7469689912eSchristos INSIST(dcurrent->serial <= dparent->serial); 7479689912eSchristos if (dcurrent->serial == dparent->serial || 7489689912eSchristos IGNORE(dcurrent)) 7499689912eSchristos { 7509689912eSchristos if (down_next != NULL) { 7519689912eSchristos down_next->next = dparent; 7529689912eSchristos } 7539689912eSchristos dparent->down = down_next; 7549689912eSchristos dns_slabheader_destroy(&dcurrent); 7559689912eSchristos } else { 7569689912eSchristos dparent = dcurrent; 7579689912eSchristos } 7589689912eSchristos } 7599689912eSchristos 7609689912eSchristos /* 7619689912eSchristos * We've now eliminated all IGNORE datasets with the possible 7629689912eSchristos * exception of current, which we now check. 7639689912eSchristos */ 7649689912eSchristos if (IGNORE(current)) { 7659689912eSchristos down_next = current->down; 7669689912eSchristos if (down_next == NULL) { 7679689912eSchristos if (top_prev != NULL) { 7689689912eSchristos top_prev->next = current->next; 7699689912eSchristos } else { 7709689912eSchristos node->data = current->next; 7719689912eSchristos } 7729689912eSchristos dns_slabheader_destroy(¤t); 7739689912eSchristos /* 7749689912eSchristos * current no longer exists, so we can 7759689912eSchristos * just continue with the loop. 7769689912eSchristos */ 7779689912eSchristos continue; 7789689912eSchristos } else { 7799689912eSchristos /* 7809689912eSchristos * Pull up current->down, making it the new 7819689912eSchristos * current. 7829689912eSchristos */ 7839689912eSchristos if (top_prev != NULL) { 7849689912eSchristos top_prev->next = down_next; 7859689912eSchristos } else { 7869689912eSchristos node->data = down_next; 7879689912eSchristos } 7889689912eSchristos down_next->next = top_next; 7899689912eSchristos dns_slabheader_destroy(¤t); 7909689912eSchristos current = down_next; 7919689912eSchristos } 7929689912eSchristos } 7939689912eSchristos 7949689912eSchristos /* 7959689912eSchristos * We now try to find the first down node less than the 7969689912eSchristos * least serial. 7979689912eSchristos */ 7989689912eSchristos dparent = current; 7999689912eSchristos for (dcurrent = current->down; dcurrent != NULL; 8009689912eSchristos dcurrent = down_next) 8019689912eSchristos { 8029689912eSchristos down_next = dcurrent->down; 8039689912eSchristos if (dcurrent->serial < least_serial) { 8049689912eSchristos break; 8059689912eSchristos } 8069689912eSchristos dparent = dcurrent; 8079689912eSchristos } 8089689912eSchristos 8099689912eSchristos /* 8109689912eSchristos * If there is a such an rdataset, delete it and any older 8119689912eSchristos * versions. 8129689912eSchristos */ 8139689912eSchristos if (dcurrent != NULL) { 8149689912eSchristos do { 8159689912eSchristos down_next = dcurrent->down; 8169689912eSchristos INSIST(dcurrent->serial <= least_serial); 8179689912eSchristos dns_slabheader_destroy(&dcurrent); 8189689912eSchristos dcurrent = down_next; 8199689912eSchristos } while (dcurrent != NULL); 8209689912eSchristos dparent->down = NULL; 8219689912eSchristos } 8229689912eSchristos 8239689912eSchristos /* 8249689912eSchristos * Note. The serial number of 'current' might be less than 8259689912eSchristos * least_serial too, but we cannot delete it because it is 8269689912eSchristos * the most recent version. 8279689912eSchristos */ 8289689912eSchristos if (current->down != NULL) { 8299689912eSchristos still_dirty = true; 8309689912eSchristos } 8319689912eSchristos top_prev = current; 8329689912eSchristos } 8339689912eSchristos if (!still_dirty) { 8349689912eSchristos node->dirty = false; 8359689912eSchristos } 8369689912eSchristos } 8379689912eSchristos 8389689912eSchristos /* 8399689912eSchristos * Caller must be holding the node lock; either the read or write lock. 8409689912eSchristos * Note that the lock must be held even when node references are 8419689912eSchristos * atomically modified; in that case the decrement operation itself does not 8429689912eSchristos * have to be protected, but we must avoid a race condition where multiple 8439689912eSchristos * threads are decreasing the reference to zero simultaneously and at least 8449689912eSchristos * one of them is going to free the node. 8459689912eSchristos * 8469689912eSchristos * This decrements both the internal and external node reference counters. 8479689912eSchristos * If the external reference count drops to zero, then the node lock 8489689912eSchristos * reference count is also decremented. 8499689912eSchristos * 8509689912eSchristos * (NOTE: Decrementing the reference count of a node to zero does 8519689912eSchristos * not mean it will be immediately freed.) 8529689912eSchristos */ 8539689912eSchristos static void 8549689912eSchristos decref(qpzonedb_t *qpdb, qpznode_t *node, uint32_t least_serial, 8559689912eSchristos isc_rwlocktype_t *nlocktypep DNS__DB_FLARG) { 8569689912eSchristos db_nodelock_t *nodelock = NULL; 8579689912eSchristos int bucket = node->locknum; 8589689912eSchristos uint_fast32_t refs; 8599689912eSchristos 8609689912eSchristos REQUIRE(*nlocktypep != isc_rwlocktype_none); 8619689912eSchristos 8629689912eSchristos nodelock = &qpdb->node_locks[bucket]; 8639689912eSchristos 8649689912eSchristos /* Handle easy and typical case first. */ 8659689912eSchristos if (!node->dirty && (node->data != NULL || node == qpdb->origin || 8669689912eSchristos node == qpdb->nsec3_origin)) 8679689912eSchristos { 8689689912eSchristos refs = isc_refcount_decrement(&node->erefs); 8699689912eSchristos #if DNS_DB_NODETRACE 8709689912eSchristos fprintf(stderr, 8719689912eSchristos "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n", 8729689912eSchristos func, file, line, node, refs - 1); 8739689912eSchristos #else 8749689912eSchristos UNUSED(refs); 8759689912eSchristos #endif 8769689912eSchristos if (refs == 1) { 8779689912eSchristos refs = isc_refcount_decrement(&nodelock->references); 8789689912eSchristos #if DNS_DB_NODETRACE 8799689912eSchristos fprintf(stderr, 8809689912eSchristos "decr:nodelock:%s:%s:%u:%p:%p->references = " 8819689912eSchristos "%" PRIuFAST32 "\n", 8829689912eSchristos func, file, line, node, nodelock, refs - 1); 8839689912eSchristos #else 8849689912eSchristos UNUSED(refs); 8859689912eSchristos #endif 8869689912eSchristos } 8879689912eSchristos goto done; 8889689912eSchristos } 8899689912eSchristos 8909689912eSchristos /* Upgrade the lock? */ 8919689912eSchristos if (*nlocktypep == isc_rwlocktype_read) { 8929689912eSchristos NODE_FORCEUPGRADE(&nodelock->lock, nlocktypep); 8939689912eSchristos } 8949689912eSchristos 8959689912eSchristos refs = isc_refcount_decrement(&node->erefs); 8969689912eSchristos #if DNS_DB_NODETRACE 8979689912eSchristos fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n", 8989689912eSchristos func, file, line, node, refs - 1); 8999689912eSchristos #endif 9009689912eSchristos if (refs == 1) { 9019689912eSchristos if (node->dirty) { 9029689912eSchristos if (least_serial == 0) { 9039689912eSchristos /* 9049689912eSchristos * Caller doesn't know the least serial. 9059689912eSchristos * Get it. 9069689912eSchristos */ 9079689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 9089689912eSchristos least_serial = qpdb->least_serial; 9099689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 9109689912eSchristos } 9119689912eSchristos clean_zone_node(node, least_serial); 9129689912eSchristos } 9139689912eSchristos 9149689912eSchristos refs = isc_refcount_decrement(&nodelock->references); 9159689912eSchristos #if DNS_DB_NODETRACE 9169689912eSchristos fprintf(stderr, 9179689912eSchristos "decr:nodelock:%s:%s:%u:%p:%p->references = " 9189689912eSchristos "%" PRIuFAST32 "\n", 9199689912eSchristos func, file, line, node, nodelock, refs - 1); 9209689912eSchristos #else 9219689912eSchristos UNUSED(refs); 9229689912eSchristos #endif 9239689912eSchristos } 9249689912eSchristos 9259689912eSchristos done: 9269689912eSchristos qpznode_unref(node); 9279689912eSchristos } 9289689912eSchristos 9299689912eSchristos static void 9309689912eSchristos bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header, 9319689912eSchristos isc_stdtime_t now, dns_rdataset_t *rdataset DNS__DB_FLARG) { 9329689912eSchristos if (rdataset == NULL) { 9339689912eSchristos return; 9349689912eSchristos } 9359689912eSchristos 9369689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 9379689912eSchristos 9389689912eSchristos INSIST(rdataset->methods == NULL); /* We must be disassociated. */ 9399689912eSchristos 9409689912eSchristos rdataset->methods = &dns_rdataslab_rdatasetmethods; 9419689912eSchristos rdataset->rdclass = qpdb->common.rdclass; 9429689912eSchristos rdataset->type = DNS_TYPEPAIR_TYPE(header->type); 9439689912eSchristos rdataset->covers = DNS_TYPEPAIR_COVERS(header->type); 9449689912eSchristos rdataset->ttl = header->ttl - now; 9459689912eSchristos rdataset->trust = header->trust; 9469689912eSchristos 9479689912eSchristos if (OPTOUT(header)) { 9489689912eSchristos rdataset->attributes |= DNS_RDATASETATTR_OPTOUT; 9499689912eSchristos } 9509689912eSchristos 9519689912eSchristos rdataset->count = atomic_fetch_add_relaxed(&header->count, 1); 9529689912eSchristos 9539689912eSchristos rdataset->slab.db = (dns_db_t *)qpdb; 9549689912eSchristos rdataset->slab.node = (dns_dbnode_t *)node; 9559689912eSchristos rdataset->slab.raw = dns_slabheader_raw(header); 9569689912eSchristos rdataset->slab.iter_pos = NULL; 9579689912eSchristos rdataset->slab.iter_count = 0; 9589689912eSchristos 9599689912eSchristos /* 9609689912eSchristos * Add noqname proof. 9619689912eSchristos */ 9629689912eSchristos rdataset->slab.noqname = header->noqname; 9639689912eSchristos if (header->noqname != NULL) { 9649689912eSchristos rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; 9659689912eSchristos } 9669689912eSchristos rdataset->slab.closest = header->closest; 9679689912eSchristos if (header->closest != NULL) { 9689689912eSchristos rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; 9699689912eSchristos } 9709689912eSchristos 9719689912eSchristos /* 9729689912eSchristos * Copy out re-signing information. 9739689912eSchristos */ 9749689912eSchristos if (RESIGN(header)) { 9759689912eSchristos rdataset->attributes |= DNS_RDATASETATTR_RESIGN; 9769689912eSchristos rdataset->resign = (header->resign << 1) | header->resign_lsb; 9779689912eSchristos } else { 9789689912eSchristos rdataset->resign = 0; 9799689912eSchristos } 9809689912eSchristos } 9819689912eSchristos 9829689912eSchristos static void 9839689912eSchristos setnsec3parameters(dns_db_t *db, qpz_version_t *version) { 9849689912eSchristos qpznode_t *node = NULL; 9859689912eSchristos dns_rdata_nsec3param_t nsec3param; 9869689912eSchristos dns_rdata_t rdata = DNS_RDATA_INIT; 9879689912eSchristos isc_region_t region; 9889689912eSchristos isc_result_t result; 9899689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 9909689912eSchristos unsigned char *raw; /* RDATASLAB */ 9919689912eSchristos unsigned int count, length; 9929689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 9939689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 9949689912eSchristos 9959689912eSchristos version->havensec3 = false; 9969689912eSchristos node = qpdb->origin; 9979689912eSchristos NODE_RDLOCK(&(qpdb->node_locks[node->locknum].lock), &nlocktype); 9989689912eSchristos for (header = node->data; header != NULL; header = header_next) { 9999689912eSchristos header_next = header->next; 10009689912eSchristos do { 10019689912eSchristos if (header->serial <= version->serial && 10029689912eSchristos !IGNORE(header)) 10039689912eSchristos { 10049689912eSchristos if (NONEXISTENT(header)) { 10059689912eSchristos header = NULL; 10069689912eSchristos } 10079689912eSchristos break; 10089689912eSchristos } else { 10099689912eSchristos header = header->down; 10109689912eSchristos } 10119689912eSchristos } while (header != NULL); 10129689912eSchristos 10139689912eSchristos if (header != NULL && 10149689912eSchristos (header->type == dns_rdatatype_nsec3param)) 10159689912eSchristos { 10169689912eSchristos /* 10179689912eSchristos * Find an NSEC3PARAM with a supported algorithm. 10189689912eSchristos */ 10199689912eSchristos raw = dns_slabheader_raw(header); 10209689912eSchristos count = raw[0] * 256 + raw[1]; /* count */ 10219689912eSchristos raw += DNS_RDATASET_COUNT + DNS_RDATASET_LENGTH; 10229689912eSchristos while (count-- > 0U) { 10239689912eSchristos length = raw[0] * 256 + raw[1]; 10249689912eSchristos raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; 10259689912eSchristos region.base = raw; 10269689912eSchristos region.length = length; 10279689912eSchristos raw += length; 10289689912eSchristos dns_rdata_fromregion( 10299689912eSchristos &rdata, qpdb->common.rdclass, 10309689912eSchristos dns_rdatatype_nsec3param, ®ion); 10319689912eSchristos result = dns_rdata_tostruct(&rdata, &nsec3param, 10329689912eSchristos NULL); 10339689912eSchristos INSIST(result == ISC_R_SUCCESS); 10349689912eSchristos dns_rdata_reset(&rdata); 10359689912eSchristos 10369689912eSchristos if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && 10379689912eSchristos !dns_nsec3_supportedhash(nsec3param.hash)) 10389689912eSchristos { 10399689912eSchristos continue; 10409689912eSchristos } 10419689912eSchristos 10429689912eSchristos if (nsec3param.flags != 0) { 10439689912eSchristos continue; 10449689912eSchristos } 10459689912eSchristos 10469689912eSchristos memmove(version->salt, nsec3param.salt, 10479689912eSchristos nsec3param.salt_length); 10489689912eSchristos version->hash = nsec3param.hash; 10499689912eSchristos version->salt_length = nsec3param.salt_length; 10509689912eSchristos version->iterations = nsec3param.iterations; 10519689912eSchristos version->flags = nsec3param.flags; 10529689912eSchristos version->havensec3 = true; 10539689912eSchristos /* 10549689912eSchristos * Look for a better algorithm than the 10559689912eSchristos * unknown test algorithm. 10569689912eSchristos */ 10579689912eSchristos if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { 10589689912eSchristos goto unlock; 10599689912eSchristos } 10609689912eSchristos } 10619689912eSchristos } 10629689912eSchristos } 10639689912eSchristos unlock: 10649689912eSchristos NODE_UNLOCK(&(qpdb->node_locks[node->locknum].lock), &nlocktype); 10659689912eSchristos } 10669689912eSchristos 10679689912eSchristos static void 10689689912eSchristos cleanup_nondirty(qpz_version_t *version, qpz_changedlist_t *cleanup_list) { 10699689912eSchristos qpz_changed_t *changed = NULL, *next_changed = NULL; 10709689912eSchristos 10719689912eSchristos /* 10729689912eSchristos * If the changed record is dirty, then an update created multiple 10739689912eSchristos * versions of a given rdataset. We keep this list until we're the 10749689912eSchristos * least open version, at which point it's safe to get rid of any 10759689912eSchristos * older versions. 10769689912eSchristos * 10779689912eSchristos * If the changed record isn't dirty, then we don't need it anymore 10789689912eSchristos * since we're committing and not rolling back. 10799689912eSchristos * 10809689912eSchristos * The caller must be holding the database lock. 10819689912eSchristos */ 10829689912eSchristos for (changed = HEAD(version->changed_list); changed != NULL; 10839689912eSchristos changed = next_changed) 10849689912eSchristos { 10859689912eSchristos next_changed = NEXT(changed, link); 10869689912eSchristos if (!changed->dirty) { 10879689912eSchristos UNLINK(version->changed_list, changed, link); 10889689912eSchristos APPEND(*cleanup_list, changed, link); 10899689912eSchristos } 10909689912eSchristos } 10919689912eSchristos } 10929689912eSchristos 10939689912eSchristos static void 10949689912eSchristos setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) { 10959689912eSchristos dns_rdataset_t keyset; 10969689912eSchristos dns_rdataset_t nsecset, signsecset; 10979689912eSchristos bool haszonekey = false; 10989689912eSchristos bool hasnsec = false; 10999689912eSchristos isc_result_t result; 11009689912eSchristos 11019689912eSchristos dns_rdataset_init(&keyset); 11029689912eSchristos result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey, 11039689912eSchristos 0, 0, &keyset, NULL); 11049689912eSchristos if (result == ISC_R_SUCCESS) { 11059689912eSchristos result = dns_rdataset_first(&keyset); 11069689912eSchristos while (result == ISC_R_SUCCESS) { 11079689912eSchristos dns_rdata_t keyrdata = DNS_RDATA_INIT; 11089689912eSchristos dns_rdataset_current(&keyset, &keyrdata); 11099689912eSchristos if (dns_zonekey_iszonekey(&keyrdata)) { 11109689912eSchristos haszonekey = true; 11119689912eSchristos break; 11129689912eSchristos } 11139689912eSchristos result = dns_rdataset_next(&keyset); 11149689912eSchristos } 11159689912eSchristos dns_rdataset_disassociate(&keyset); 11169689912eSchristos } 11179689912eSchristos if (!haszonekey) { 11189689912eSchristos version->secure = false; 11199689912eSchristos version->havensec3 = false; 11209689912eSchristos return; 11219689912eSchristos } 11229689912eSchristos 11239689912eSchristos dns_rdataset_init(&nsecset); 11249689912eSchristos dns_rdataset_init(&signsecset); 11259689912eSchristos result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec, 0, 11269689912eSchristos 0, &nsecset, &signsecset); 11279689912eSchristos if (result == ISC_R_SUCCESS) { 11289689912eSchristos if (dns_rdataset_isassociated(&signsecset)) { 11299689912eSchristos hasnsec = true; 11309689912eSchristos dns_rdataset_disassociate(&signsecset); 11319689912eSchristos } 11329689912eSchristos dns_rdataset_disassociate(&nsecset); 11339689912eSchristos } 11349689912eSchristos 11359689912eSchristos setnsec3parameters(db, version); 11369689912eSchristos 11379689912eSchristos /* 11389689912eSchristos * Do we have a valid NSEC/NSEC3 chain? 11399689912eSchristos */ 11409689912eSchristos if (version->havensec3 || hasnsec) { 11419689912eSchristos version->secure = true; 11429689912eSchristos } else { 11439689912eSchristos version->secure = false; 11449689912eSchristos } 11459689912eSchristos } 11469689912eSchristos 11479689912eSchristos static void 11489689912eSchristos currentversion(dns_db_t *db, dns_dbversion_t **versionp) { 11499689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 11509689912eSchristos qpz_version_t *version = NULL; 11519689912eSchristos 11529689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 11539689912eSchristos 11549689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 11559689912eSchristos version = qpdb->current_version; 11569689912eSchristos isc_refcount_increment(&version->references); 11579689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 11589689912eSchristos 11599689912eSchristos *versionp = (dns_dbversion_t *)version; 11609689912eSchristos } 11619689912eSchristos 11629689912eSchristos static void 11639689912eSchristos attachversion(dns_db_t *db, dns_dbversion_t *source, 11649689912eSchristos dns_dbversion_t **targetp) { 11659689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 11669689912eSchristos qpz_version_t *version = source; 11679689912eSchristos 11689689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 11699689912eSchristos INSIST(version != NULL && version->qpdb == qpdb); 11709689912eSchristos 11719689912eSchristos isc_refcount_increment(&version->references); 11729689912eSchristos 11739689912eSchristos *targetp = version; 11749689912eSchristos } 11759689912eSchristos 11769689912eSchristos static isc_result_t 11779689912eSchristos newversion(dns_db_t *db, dns_dbversion_t **versionp) { 11789689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 11799689912eSchristos qpz_version_t *version = NULL; 11809689912eSchristos 11819689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 11829689912eSchristos REQUIRE(versionp != NULL && *versionp == NULL); 11839689912eSchristos REQUIRE(qpdb->future_version == NULL); 11849689912eSchristos 11859689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 11869689912eSchristos INSIST(qpdb->next_serial != 0); 11879689912eSchristos version = allocate_version(qpdb->common.mctx, qpdb->next_serial, 1, 11889689912eSchristos true); 11899689912eSchristos version->qpdb = qpdb; 11909689912eSchristos version->secure = qpdb->current_version->secure; 11919689912eSchristos version->havensec3 = qpdb->current_version->havensec3; 11929689912eSchristos if (version->havensec3) { 11939689912eSchristos version->flags = qpdb->current_version->flags; 11949689912eSchristos version->iterations = qpdb->current_version->iterations; 11959689912eSchristos version->hash = qpdb->current_version->hash; 11969689912eSchristos version->salt_length = qpdb->current_version->salt_length; 11979689912eSchristos memmove(version->salt, qpdb->current_version->salt, 11989689912eSchristos version->salt_length); 11999689912eSchristos } 12009689912eSchristos 12019689912eSchristos version->records = qpdb->current_version->records; 12029689912eSchristos version->xfrsize = qpdb->current_version->xfrsize; 12039689912eSchristos 12049689912eSchristos qpdb->next_serial++; 12059689912eSchristos qpdb->future_version = version; 12069689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 12079689912eSchristos 12089689912eSchristos *versionp = version; 12099689912eSchristos 12109689912eSchristos return ISC_R_SUCCESS; 12119689912eSchristos } 12129689912eSchristos 12139689912eSchristos static void 12149689912eSchristos resigninsert(qpzonedb_t *qpdb, dns_slabheader_t *newheader) { 12159689912eSchristos REQUIRE(newheader->heap_index == 0); 12169689912eSchristos REQUIRE(!ISC_LINK_LINKED(newheader, link)); 12179689912eSchristos 12189689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 12199689912eSchristos isc_heap_insert(qpdb->heap, newheader); 12209689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 12219689912eSchristos 12229689912eSchristos newheader->heap = qpdb->heap; 12239689912eSchristos } 12249689912eSchristos 12259689912eSchristos static void 12269689912eSchristos resigndelete(qpzonedb_t *qpdb, qpz_version_t *version, 12279689912eSchristos dns_slabheader_t *header DNS__DB_FLARG) { 12289689912eSchristos if (header == NULL || header->heap_index == 0) { 12299689912eSchristos return; 12309689912eSchristos } 12319689912eSchristos 12329689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 12339689912eSchristos isc_heap_delete(qpdb->heap, header->heap_index); 12349689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 12359689912eSchristos 12369689912eSchristos header->heap_index = 0; 12379689912eSchristos newref(qpdb, HEADERNODE(header) DNS__DB_FLARG_PASS); 12389689912eSchristos ISC_LIST_APPEND(version->resigned_list, header, link); 12399689912eSchristos } 12409689912eSchristos 12419689912eSchristos static void 12429689912eSchristos make_least_version(qpzonedb_t *qpdb, qpz_version_t *version, 12439689912eSchristos qpz_changedlist_t *cleanup_list) { 12449689912eSchristos qpdb->least_serial = version->serial; 12459689912eSchristos *cleanup_list = version->changed_list; 12469689912eSchristos ISC_LIST_INIT(version->changed_list); 12479689912eSchristos } 12489689912eSchristos 12499689912eSchristos static void 12509689912eSchristos rollback_node(qpznode_t *node, uint32_t serial) { 12519689912eSchristos dns_slabheader_t *header = NULL, *dcurrent = NULL; 12529689912eSchristos bool make_dirty = false; 12539689912eSchristos 12549689912eSchristos /* 12559689912eSchristos * We set the IGNORE attribute on rdatasets with serial number 12569689912eSchristos * 'serial'. When the reference count goes to zero, these rdatasets 12579689912eSchristos * will be cleaned up; until that time, they will be ignored. 12589689912eSchristos */ 12599689912eSchristos for (header = node->data; header != NULL; header = header->next) { 12609689912eSchristos if (header->serial == serial) { 12619689912eSchristos DNS_SLABHEADER_SETATTR(header, 12629689912eSchristos DNS_SLABHEADERATTR_IGNORE); 12639689912eSchristos make_dirty = true; 12649689912eSchristos } 12659689912eSchristos for (dcurrent = header->down; dcurrent != NULL; 12669689912eSchristos dcurrent = dcurrent->down) 12679689912eSchristos { 12689689912eSchristos if (dcurrent->serial == serial) { 12699689912eSchristos DNS_SLABHEADER_SETATTR( 12709689912eSchristos dcurrent, DNS_SLABHEADERATTR_IGNORE); 12719689912eSchristos make_dirty = true; 12729689912eSchristos } 12739689912eSchristos } 12749689912eSchristos } 12759689912eSchristos if (make_dirty) { 12769689912eSchristos node->dirty = true; 12779689912eSchristos } 12789689912eSchristos } 12799689912eSchristos 12809689912eSchristos static void 12819689912eSchristos closeversion(dns_db_t *db, dns_dbversion_t **versionp, 12829689912eSchristos bool commit DNS__DB_FLARG) { 12839689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 12849689912eSchristos qpz_version_t *version = NULL, *cleanup_version = NULL; 12859689912eSchristos qpz_version_t *least_greater = NULL; 12869689912eSchristos qpznode_t *node = NULL; 12879689912eSchristos bool rollback = false; 12889689912eSchristos qpz_changed_t *changed = NULL, *next_changed = NULL; 12899689912eSchristos qpz_changedlist_t cleanup_list; 12909689912eSchristos dns_slabheaderlist_t resigned_list; 12919689912eSchristos dns_slabheader_t *header = NULL; 12929689912eSchristos uint32_t serial, least_serial; 12939689912eSchristos 12949689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 12959689912eSchristos version = (qpz_version_t *)*versionp; 12969689912eSchristos INSIST(version->qpdb == qpdb); 12979689912eSchristos 12989689912eSchristos if (isc_refcount_decrement(&version->references) > 1) { 12999689912eSchristos *versionp = NULL; 13009689912eSchristos return; 13019689912eSchristos } 13029689912eSchristos 13039689912eSchristos ISC_LIST_INIT(cleanup_list); 13049689912eSchristos ISC_LIST_INIT(resigned_list); 13059689912eSchristos 13069689912eSchristos /* 13079689912eSchristos * Update the zone's secure status in version before making 13089689912eSchristos * it the current version. 13099689912eSchristos */ 13109689912eSchristos if (version->writer && commit) { 13119689912eSchristos setsecure(db, version, qpdb->origin); 13129689912eSchristos } 13139689912eSchristos 13149689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 13159689912eSchristos serial = version->serial; 13169689912eSchristos if (version->writer) { 13179689912eSchristos if (commit) { 13189689912eSchristos unsigned int cur_ref; 13199689912eSchristos qpz_version_t *cur_version = NULL; 13209689912eSchristos 13219689912eSchristos INSIST(version == qpdb->future_version); 13229689912eSchristos /* 13239689912eSchristos * The current version is going to be replaced. 13249689912eSchristos * Release the (likely last) reference to it from the 13259689912eSchristos * DB itself and unlink it from the open list. 13269689912eSchristos */ 13279689912eSchristos cur_version = qpdb->current_version; 13289689912eSchristos cur_ref = isc_refcount_decrement( 13299689912eSchristos &cur_version->references); 13309689912eSchristos if (cur_ref == 1) { 13319689912eSchristos (void)isc_refcount_current( 13329689912eSchristos &cur_version->references); 13339689912eSchristos if (cur_version->serial == qpdb->least_serial) { 13349689912eSchristos INSIST(EMPTY( 13359689912eSchristos cur_version->changed_list)); 13369689912eSchristos } 13379689912eSchristos UNLINK(qpdb->open_versions, cur_version, link); 13389689912eSchristos } 13399689912eSchristos if (EMPTY(qpdb->open_versions)) { 13409689912eSchristos /* 13419689912eSchristos * We're going to become the least open 13429689912eSchristos * version. 13439689912eSchristos */ 13449689912eSchristos make_least_version(qpdb, version, 13459689912eSchristos &cleanup_list); 13469689912eSchristos } else { 13479689912eSchristos /* 13489689912eSchristos * Some other open version is the 13499689912eSchristos * least version. We can't cleanup 13509689912eSchristos * records that were changed in this 13519689912eSchristos * version because the older versions 13529689912eSchristos * may still be in use by an open 13539689912eSchristos * version. 13549689912eSchristos * 13559689912eSchristos * We can, however, discard the 13569689912eSchristos * changed records for things that 13579689912eSchristos * we've added that didn't exist in 13589689912eSchristos * prior versions. 13599689912eSchristos */ 13609689912eSchristos cleanup_nondirty(version, &cleanup_list); 13619689912eSchristos } 13629689912eSchristos /* 13639689912eSchristos * If the (soon to be former) current version 13649689912eSchristos * isn't being used by anyone, we can clean 13659689912eSchristos * it up. 13669689912eSchristos */ 13679689912eSchristos if (cur_ref == 1) { 13689689912eSchristos cleanup_version = cur_version; 13699689912eSchristos APPENDLIST(version->changed_list, 13709689912eSchristos cleanup_version->changed_list, link); 13719689912eSchristos } 13729689912eSchristos /* 13739689912eSchristos * Become the current version. 13749689912eSchristos */ 13759689912eSchristos version->writer = false; 13769689912eSchristos qpdb->current_version = version; 13779689912eSchristos qpdb->current_serial = version->serial; 13789689912eSchristos qpdb->future_version = NULL; 13799689912eSchristos 13809689912eSchristos /* 13819689912eSchristos * Keep the current version in the open list, and 13829689912eSchristos * gain a reference for the DB itself (see the DB 13839689912eSchristos * creation function below). This must be the only 13849689912eSchristos * case where we need to increment the counter from 13859689912eSchristos * zero and need to use isc_refcount_increment0(). 13869689912eSchristos */ 13879689912eSchristos INSIST(isc_refcount_increment0(&version->references) == 13889689912eSchristos 0); 13899689912eSchristos PREPEND(qpdb->open_versions, qpdb->current_version, 13909689912eSchristos link); 13919689912eSchristos resigned_list = version->resigned_list; 13929689912eSchristos ISC_LIST_INIT(version->resigned_list); 13939689912eSchristos } else { 13949689912eSchristos /* 13959689912eSchristos * We're rolling back this transaction. 13969689912eSchristos */ 13979689912eSchristos cleanup_list = version->changed_list; 13989689912eSchristos ISC_LIST_INIT(version->changed_list); 13999689912eSchristos resigned_list = version->resigned_list; 14009689912eSchristos ISC_LIST_INIT(version->resigned_list); 14019689912eSchristos rollback = true; 14029689912eSchristos cleanup_version = version; 14039689912eSchristos qpdb->future_version = NULL; 14049689912eSchristos } 14059689912eSchristos } else { 14069689912eSchristos if (version != qpdb->current_version) { 14079689912eSchristos /* 14089689912eSchristos * There are no external or internal references 14099689912eSchristos * to this version and it can be cleaned up. 14109689912eSchristos */ 14119689912eSchristos cleanup_version = version; 14129689912eSchristos 14139689912eSchristos /* 14149689912eSchristos * Find the version with the least serial 14159689912eSchristos * number greater than ours. 14169689912eSchristos */ 14179689912eSchristos least_greater = PREV(version, link); 14189689912eSchristos if (least_greater == NULL) { 14199689912eSchristos least_greater = qpdb->current_version; 14209689912eSchristos } 14219689912eSchristos 14229689912eSchristos INSIST(version->serial < least_greater->serial); 14239689912eSchristos /* 14249689912eSchristos * Is this the least open version? 14259689912eSchristos */ 14269689912eSchristos if (version->serial == qpdb->least_serial) { 14279689912eSchristos /* 14289689912eSchristos * Yes. Install the new least open 14299689912eSchristos * version. 14309689912eSchristos */ 14319689912eSchristos make_least_version(qpdb, least_greater, 14329689912eSchristos &cleanup_list); 14339689912eSchristos } else { 14349689912eSchristos /* 14359689912eSchristos * Add any unexecuted cleanups to 14369689912eSchristos * those of the least greater version. 14379689912eSchristos */ 14389689912eSchristos APPENDLIST(least_greater->changed_list, 14399689912eSchristos version->changed_list, link); 14409689912eSchristos } 14419689912eSchristos } else if (version->serial == qpdb->least_serial) { 14429689912eSchristos INSIST(EMPTY(version->changed_list)); 14439689912eSchristos } 14449689912eSchristos UNLINK(qpdb->open_versions, version, link); 14459689912eSchristos } 14469689912eSchristos least_serial = qpdb->least_serial; 14479689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 14489689912eSchristos 14499689912eSchristos if (cleanup_version != NULL) { 14509689912eSchristos isc_refcount_destroy(&cleanup_version->references); 14519689912eSchristos INSIST(EMPTY(cleanup_version->changed_list)); 14529689912eSchristos free_gluetable(cleanup_version->glue_table); 14539689912eSchristos isc_rwlock_destroy(&cleanup_version->rwlock); 14549689912eSchristos isc_mem_put(qpdb->common.mctx, cleanup_version, 14559689912eSchristos sizeof(*cleanup_version)); 14569689912eSchristos } 14579689912eSchristos 14589689912eSchristos /* 14599689912eSchristos * Commit/rollback re-signed headers. 14609689912eSchristos */ 14619689912eSchristos for (header = HEAD(resigned_list); header != NULL; 14629689912eSchristos header = HEAD(resigned_list)) 14639689912eSchristos { 14649689912eSchristos isc_rwlock_t *lock = NULL; 14659689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 14669689912eSchristos 14679689912eSchristos ISC_LIST_UNLINK(resigned_list, header, link); 14689689912eSchristos 14699689912eSchristos lock = &qpdb->node_locks[HEADERNODE(header)->locknum].lock; 14709689912eSchristos NODE_WRLOCK(lock, &nlocktype); 14719689912eSchristos if (rollback && !IGNORE(header)) { 14729689912eSchristos resigninsert(qpdb, header); 14739689912eSchristos } 14749689912eSchristos decref(qpdb, HEADERNODE(header), least_serial, 14759689912eSchristos &nlocktype DNS__DB_FLARG_PASS); 14769689912eSchristos NODE_UNLOCK(lock, &nlocktype); 14779689912eSchristos } 14789689912eSchristos 14799689912eSchristos if (EMPTY(cleanup_list)) { 14809689912eSchristos *versionp = NULL; 14819689912eSchristos return; 14829689912eSchristos } 14839689912eSchristos 14849689912eSchristos for (changed = HEAD(cleanup_list); changed != NULL; 14859689912eSchristos changed = next_changed) 14869689912eSchristos { 14879689912eSchristos isc_rwlock_t *lock = NULL; 14889689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 14899689912eSchristos 14909689912eSchristos next_changed = NEXT(changed, link); 14919689912eSchristos node = changed->node; 14929689912eSchristos lock = &qpdb->node_locks[node->locknum].lock; 14939689912eSchristos 14949689912eSchristos NODE_WRLOCK(lock, &nlocktype); 14959689912eSchristos if (rollback) { 14969689912eSchristos rollback_node(node, serial); 14979689912eSchristos } 14989689912eSchristos decref(qpdb, node, least_serial, &nlocktype DNS__DB_FILELINE); 14999689912eSchristos 15009689912eSchristos NODE_UNLOCK(lock, &nlocktype); 15019689912eSchristos 15029689912eSchristos isc_mem_put(qpdb->common.mctx, changed, sizeof(*changed)); 15039689912eSchristos } 15049689912eSchristos 15059689912eSchristos *versionp = NULL; 15069689912eSchristos } 15079689912eSchristos 15089689912eSchristos static isc_result_t 15099689912eSchristos findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, 15109689912eSchristos dns_rdatatype_t type, dns_rdatatype_t covers, 15119689912eSchristos isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset, 15129689912eSchristos dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 15139689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 15149689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 15159689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 15169689912eSchristos dns_slabheader_t *found = NULL, *foundsig = NULL; 15179689912eSchristos uint32_t serial; 15189689912eSchristos qpz_version_t *version = dbversion; 15199689912eSchristos bool close_version = false; 15209689912eSchristos dns_typepair_t matchtype, sigmatchtype; 15219689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 15229689912eSchristos 15239689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 15249689912eSchristos REQUIRE(type != dns_rdatatype_any); 15259689912eSchristos INSIST(version == NULL || version->qpdb == qpdb); 15269689912eSchristos 15279689912eSchristos if (version == NULL) { 15289689912eSchristos currentversion(db, (dns_dbversion_t **)&version); 15299689912eSchristos close_version = true; 15309689912eSchristos } 15319689912eSchristos serial = version->serial; 15329689912eSchristos 15339689912eSchristos NODE_RDLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 15349689912eSchristos 15359689912eSchristos matchtype = DNS_TYPEPAIR_VALUE(type, covers); 15369689912eSchristos if (covers == 0) { 15379689912eSchristos sigmatchtype = DNS_SIGTYPE(type); 15389689912eSchristos } else { 15399689912eSchristos sigmatchtype = 0; 15409689912eSchristos } 15419689912eSchristos 15429689912eSchristos for (header = node->data; header != NULL; header = header_next) { 15439689912eSchristos header_next = header->next; 15449689912eSchristos do { 15459689912eSchristos if (header->serial <= serial && !IGNORE(header)) { 15469689912eSchristos if (NONEXISTENT(header)) { 15479689912eSchristos header = NULL; 15489689912eSchristos } 15499689912eSchristos break; 15509689912eSchristos } else { 15519689912eSchristos header = header->down; 15529689912eSchristos } 15539689912eSchristos } while (header != NULL); 15549689912eSchristos if (header != NULL) { 15559689912eSchristos /* 15569689912eSchristos * We have an active, extant rdataset. If it's a 15579689912eSchristos * type we're looking for, remember it. 15589689912eSchristos */ 15599689912eSchristos if (header->type == matchtype) { 15609689912eSchristos found = header; 15619689912eSchristos if (foundsig != NULL) { 15629689912eSchristos break; 15639689912eSchristos } 15649689912eSchristos } else if (header->type == sigmatchtype) { 15659689912eSchristos foundsig = header; 15669689912eSchristos if (found != NULL) { 15679689912eSchristos break; 15689689912eSchristos } 15699689912eSchristos } 15709689912eSchristos } 15719689912eSchristos } 15729689912eSchristos if (found != NULL) { 15739689912eSchristos bindrdataset(qpdb, node, found, 0, rdataset DNS__DB_FLARG_PASS); 15749689912eSchristos if (foundsig != NULL) { 15759689912eSchristos bindrdataset(qpdb, node, foundsig, 0, 15769689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 15779689912eSchristos } 15789689912eSchristos } 15799689912eSchristos 15809689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 15819689912eSchristos 15829689912eSchristos if (close_version) { 15839689912eSchristos closeversion(db, (dns_dbversion_t **)&version, 15849689912eSchristos false DNS__DB_FLARG_PASS); 15859689912eSchristos } 15869689912eSchristos 15879689912eSchristos if (found == NULL) { 15889689912eSchristos return ISC_R_NOTFOUND; 15899689912eSchristos } 15909689912eSchristos 15919689912eSchristos return ISC_R_SUCCESS; 15929689912eSchristos } 15939689912eSchristos 15949689912eSchristos static bool 15959689912eSchristos delegating_type(qpzonedb_t *qpdb, qpznode_t *node, dns_typepair_t type) { 15969689912eSchristos return type == dns_rdatatype_dname || 15979689912eSchristos (type == dns_rdatatype_ns && 15989689912eSchristos (node != qpdb->origin || IS_STUB(qpdb))); 15999689912eSchristos } 16009689912eSchristos 16019689912eSchristos static void 16029689912eSchristos loading_addnode(qpz_load_t *loadctx, const dns_name_t *name, 16039689912eSchristos dns_rdatatype_t type, dns_rdatatype_t covers, 16049689912eSchristos qpznode_t **nodep) { 16059689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db; 16069689912eSchristos isc_result_t result; 16079689912eSchristos qpznode_t *node = NULL, *nsecnode = NULL; 16089689912eSchristos 16099689912eSchristos if (type == dns_rdatatype_nsec3 || covers == dns_rdatatype_nsec3) { 16109689912eSchristos result = dns_qp_getname(loadctx->nsec3, name, (void **)&node, 16119689912eSchristos NULL); 16129689912eSchristos if (result == ISC_R_SUCCESS) { 16139689912eSchristos *nodep = node; 16149689912eSchristos } else { 16159689912eSchristos node = new_qpznode(qpdb, name); 16169689912eSchristos result = dns_qp_insert(loadctx->nsec3, node, 0); 16179689912eSchristos INSIST(result == ISC_R_SUCCESS); 16189689912eSchristos node->nsec = DNS_DB_NSEC_NSEC3; 16199689912eSchristos *nodep = node; 16209689912eSchristos qpznode_detach(&node); 16219689912eSchristos } 16229689912eSchristos return; 16239689912eSchristos } 16249689912eSchristos 16259689912eSchristos result = dns_qp_getname(loadctx->tree, name, (void **)&node, NULL); 16269689912eSchristos if (result == ISC_R_SUCCESS) { 16279689912eSchristos if (type == dns_rdatatype_nsec && 16289689912eSchristos node->nsec == DNS_DB_NSEC_HAS_NSEC) 16299689912eSchristos { 16309689912eSchristos goto done; 16319689912eSchristos } 16329689912eSchristos } else { 16339689912eSchristos INSIST(node == NULL); 16349689912eSchristos node = new_qpznode(qpdb, name); 16359689912eSchristos result = dns_qp_insert(loadctx->tree, node, 0); 16369689912eSchristos INSIST(result == ISC_R_SUCCESS); 16379689912eSchristos qpznode_unref(node); 16389689912eSchristos } 16399689912eSchristos if (type != dns_rdatatype_nsec) { 16409689912eSchristos goto done; 16419689912eSchristos } 16429689912eSchristos 16439689912eSchristos /* 16449689912eSchristos * We're adding an NSEC record, so create a node in the nsec tree 16459689912eSchristos * too. This tree speeds searches for closest NSECs that would 16469689912eSchristos * otherwise need to examine many irrelevant nodes in large TLDs. 16479689912eSchristos */ 16489689912eSchristos nsecnode = new_qpznode(qpdb, name); 16499689912eSchristos result = dns_qp_insert(loadctx->nsec, nsecnode, 0); 16509689912eSchristos node->nsec = DNS_DB_NSEC_HAS_NSEC; 16519689912eSchristos if (result == ISC_R_SUCCESS) { 16529689912eSchristos nsecnode->nsec = DNS_DB_NSEC_NSEC; 16539689912eSchristos } 16549689912eSchristos qpznode_detach(&nsecnode); 16559689912eSchristos 16569689912eSchristos done: 16579689912eSchristos *nodep = node; 16589689912eSchristos } 16599689912eSchristos 16609689912eSchristos static bool 16619689912eSchristos cname_and_other(qpznode_t *node, uint32_t serial) { 16629689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 16639689912eSchristos bool cname = false, other = false; 16649689912eSchristos dns_rdatatype_t rdtype; 16659689912eSchristos 16669689912eSchristos /* 16679689912eSchristos * Look for CNAME and "other data" rdatasets active in our version. 16689689912eSchristos * ("Other data" is any rdataset whose type is not KEY, NSEC, SIG 16699689912eSchristos * or RRSIG. 16709689912eSchristos */ 16719689912eSchristos for (header = node->data; header != NULL; header = header_next) { 16729689912eSchristos header_next = header->next; 16739689912eSchristos 16749689912eSchristos if (!prio_type(header->type)) { 16759689912eSchristos /* 16769689912eSchristos * CNAME is in the priority list, so if we are done 16779689912eSchristos * with priority types, we know there will not be a 16789689912eSchristos * CNAME, and are safe to skip the rest. 16799689912eSchristos */ 16809689912eSchristos return false; 16819689912eSchristos } 16829689912eSchristos 16839689912eSchristos rdtype = DNS_TYPEPAIR_TYPE(header->type); 16849689912eSchristos if (rdtype == dns_rdatatype_cname) { 16859689912eSchristos do { 16869689912eSchristos if (header->serial <= serial && !IGNORE(header)) 16879689912eSchristos { 16889689912eSchristos if (NONEXISTENT(header)) { 16899689912eSchristos header = NULL; 16909689912eSchristos } 16919689912eSchristos break; 16929689912eSchristos } 16939689912eSchristos header = header->down; 16949689912eSchristos } while (header != NULL); 16959689912eSchristos if (header != NULL) { 16969689912eSchristos cname = true; 16979689912eSchristos } 16989689912eSchristos } else if (rdtype != dns_rdatatype_key && 16999689912eSchristos rdtype != dns_rdatatype_sig && 17009689912eSchristos rdtype != dns_rdatatype_nsec && 17019689912eSchristos rdtype != dns_rdatatype_rrsig) 17029689912eSchristos { 17039689912eSchristos do { 17049689912eSchristos if (header->serial <= serial && !IGNORE(header)) 17059689912eSchristos { 17069689912eSchristos if (NONEXISTENT(header)) { 17079689912eSchristos header = NULL; 17089689912eSchristos } 17099689912eSchristos break; 17109689912eSchristos } 17119689912eSchristos header = header->down; 17129689912eSchristos } while (header != NULL); 17139689912eSchristos if (header != NULL) { 17149689912eSchristos other = true; 17159689912eSchristos } 17169689912eSchristos } 17179689912eSchristos 17189689912eSchristos if (cname && other) { 17199689912eSchristos return true; 17209689912eSchristos } 17219689912eSchristos } 17229689912eSchristos 17239689912eSchristos return false; 17249689912eSchristos } 17259689912eSchristos 17269689912eSchristos static qpz_changed_t * 17279689912eSchristos add_changed(dns_slabheader_t *header, qpz_version_t *version DNS__DB_FLARG) { 17289689912eSchristos qpz_changed_t *changed = NULL; 17299689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)header->db; 17309689912eSchristos qpznode_t *node = (qpznode_t *)header->node; 17319689912eSchristos 17329689912eSchristos changed = isc_mem_get(qpdb->common.mctx, sizeof(*changed)); 17339689912eSchristos 17349689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 17359689912eSchristos REQUIRE(version->writer); 17369689912eSchristos 17379689912eSchristos *changed = (qpz_changed_t){ .node = node }; 17389689912eSchristos ISC_LIST_INITANDAPPEND(version->changed_list, changed, link); 17399689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 17409689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 17419689912eSchristos 17429689912eSchristos return changed; 17439689912eSchristos } 17449689912eSchristos 17459689912eSchristos static uint64_t 17469689912eSchristos recordsize(dns_slabheader_t *header, unsigned int namelen) { 17479689912eSchristos return dns_rdataslab_rdatasize((unsigned char *)header, 17489689912eSchristos sizeof(*header)) + 17499689912eSchristos sizeof(dns_ttl_t) + sizeof(dns_rdatatype_t) + 17509689912eSchristos sizeof(dns_rdataclass_t) + namelen; 17519689912eSchristos } 17529689912eSchristos 17539689912eSchristos static void 17549689912eSchristos maybe_update_recordsandsize(bool add, qpz_version_t *version, 17559689912eSchristos dns_slabheader_t *header, unsigned int namelen) { 17569689912eSchristos unsigned char *hdr = (unsigned char *)header; 17579689912eSchristos size_t hdrsize = sizeof(*header); 17589689912eSchristos 17599689912eSchristos if (NONEXISTENT(header)) { 17609689912eSchristos return; 17619689912eSchristos } 17629689912eSchristos 17639689912eSchristos RWLOCK(&version->rwlock, isc_rwlocktype_write); 17649689912eSchristos if (add) { 17659689912eSchristos version->records += dns_rdataslab_count(hdr, hdrsize); 17669689912eSchristos version->xfrsize += recordsize(header, namelen); 17679689912eSchristos } else { 17689689912eSchristos version->records -= dns_rdataslab_count(hdr, hdrsize); 17699689912eSchristos version->xfrsize -= recordsize(header, namelen); 17709689912eSchristos } 17719689912eSchristos RWUNLOCK(&version->rwlock, isc_rwlocktype_write); 17729689912eSchristos } 17739689912eSchristos 17749689912eSchristos static isc_result_t 17759689912eSchristos add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, 17769689912eSchristos qpz_version_t *version, dns_slabheader_t *newheader, unsigned int options, 17779689912eSchristos bool loading, dns_rdataset_t *addedrdataset, 17789689912eSchristos isc_stdtime_t now DNS__DB_FLARG) { 17799689912eSchristos qpz_changed_t *changed = NULL; 17809689912eSchristos dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; 17819689912eSchristos dns_slabheader_t *prioheader = NULL; 17829689912eSchristos dns_slabheader_t *header = NULL; 17839689912eSchristos unsigned char *merged = NULL; 17849689912eSchristos isc_result_t result; 17859689912eSchristos bool merge = false; 17869689912eSchristos uint32_t ntypes; 17879689912eSchristos 17889689912eSchristos if ((options & DNS_DBADD_MERGE) != 0) { 17899689912eSchristos REQUIRE(version != NULL); 17909689912eSchristos merge = true; 17919689912eSchristos } 17929689912eSchristos 17939689912eSchristos if (!loading) { 17949689912eSchristos /* 17959689912eSchristos * We always add a changed record, even if no changes end up 17969689912eSchristos * being made to this node, because it's harmless and 17979689912eSchristos * simplifies the code. 17989689912eSchristos */ 17999689912eSchristos changed = add_changed(newheader, version DNS__DB_FLARG_PASS); 18009689912eSchristos } 18019689912eSchristos 18029689912eSchristos ntypes = 0; 18039689912eSchristos for (topheader = node->data; topheader != NULL; 18049689912eSchristos topheader = topheader->next) 18059689912eSchristos { 18069689912eSchristos ++ntypes; 18079689912eSchristos if (prio_type(topheader->type)) { 18089689912eSchristos prioheader = topheader; 18099689912eSchristos } 18109689912eSchristos if (topheader->type == newheader->type) { 18119689912eSchristos break; 18129689912eSchristos } 18139689912eSchristos topheader_prev = topheader; 18149689912eSchristos } 18159689912eSchristos 18169689912eSchristos /* 18179689912eSchristos * If topheader isn't NULL, we've found the right type. There may be 18189689912eSchristos * IGNORE rdatasets between the top of the chain and the first real 18199689912eSchristos * data. We skip over them. 18209689912eSchristos */ 18219689912eSchristos header = topheader; 18229689912eSchristos while (header != NULL && IGNORE(header)) { 18239689912eSchristos header = header->down; 18249689912eSchristos } 18259689912eSchristos if (header != NULL) { 18269689912eSchristos /* 18279689912eSchristos * If 'merge' is true and header isn't empty/nonexistent, 18289689912eSchristos * we'll try to create a new rdataset that is the union 18299689912eSchristos * of 'newheader' and 'header'. 18309689912eSchristos */ 18319689912eSchristos if (merge && !NONEXISTENT(header)) { 18329689912eSchristos unsigned int flags = 0; 18339689912eSchristos INSIST(version->serial >= header->serial); 18349689912eSchristos merged = NULL; 18359689912eSchristos result = ISC_R_SUCCESS; 18369689912eSchristos 18379689912eSchristos if ((options & DNS_DBADD_EXACT) != 0) { 18389689912eSchristos flags |= DNS_RDATASLAB_EXACT; 18399689912eSchristos } 18409689912eSchristos if ((options & DNS_DBADD_EXACTTTL) != 0 && 18419689912eSchristos newheader->ttl != header->ttl) 18429689912eSchristos { 18439689912eSchristos result = DNS_R_NOTEXACT; 18449689912eSchristos } else if (newheader->ttl != header->ttl) { 18459689912eSchristos flags |= DNS_RDATASLAB_FORCE; 18469689912eSchristos } 18479689912eSchristos if (result == ISC_R_SUCCESS) { 18489689912eSchristos result = dns_rdataslab_merge( 18499689912eSchristos (unsigned char *)header, 18509689912eSchristos (unsigned char *)newheader, 18519689912eSchristos (unsigned int)(sizeof(*newheader)), 18529689912eSchristos qpdb->common.mctx, qpdb->common.rdclass, 18539689912eSchristos (dns_rdatatype_t)header->type, flags, 18549689912eSchristos qpdb->maxrrperset, &merged); 18559689912eSchristos } 18569689912eSchristos if (result == ISC_R_SUCCESS) { 18579689912eSchristos /* 18589689912eSchristos * If 'header' has the same serial number as 18599689912eSchristos * we do, we could clean it up now if we knew 18609689912eSchristos * that our caller had no references to it. 18619689912eSchristos * We don't know this, however, so we leave it 18629689912eSchristos * alone. It will get cleaned up when 18639689912eSchristos * clean_zone_node() runs. 18649689912eSchristos */ 18659689912eSchristos dns_slabheader_destroy(&newheader); 18669689912eSchristos newheader = (dns_slabheader_t *)merged; 18679689912eSchristos dns_slabheader_reset(newheader, 18689689912eSchristos (dns_db_t *)qpdb, 18699689912eSchristos (dns_dbnode_t *)node); 18709689912eSchristos dns_slabheader_copycase(newheader, header); 18719689912eSchristos if (loading && RESIGN(newheader) && 18729689912eSchristos RESIGN(header) && 18739689912eSchristos resign_sooner(header, newheader)) 18749689912eSchristos { 18759689912eSchristos newheader->resign = header->resign; 18769689912eSchristos newheader->resign_lsb = 18779689912eSchristos header->resign_lsb; 18789689912eSchristos } 18799689912eSchristos } else { 18809689912eSchristos if (result == DNS_R_TOOMANYRECORDS) { 18819689912eSchristos dns__db_logtoomanyrecords( 18829689912eSchristos (dns_db_t *)qpdb, nodename, 18839689912eSchristos (dns_rdatatype_t)header->type, 18849689912eSchristos "updating", qpdb->maxrrperset); 18859689912eSchristos } 18869689912eSchristos dns_slabheader_destroy(&newheader); 18879689912eSchristos return result; 18889689912eSchristos } 18899689912eSchristos } 18909689912eSchristos 18919689912eSchristos INSIST(version->serial >= topheader->serial); 18929689912eSchristos if (loading) { 18939689912eSchristos newheader->down = NULL; 18949689912eSchristos if (RESIGN(newheader)) { 18959689912eSchristos resigninsert(qpdb, newheader); 18969689912eSchristos /* resigndelete not needed here */ 18979689912eSchristos } 18989689912eSchristos 18999689912eSchristos /* 19009689912eSchristos * There are no other references to 'header' when 19019689912eSchristos * loading, so we MAY clean up 'header' now. 19029689912eSchristos * Since we don't generate changed records when 19039689912eSchristos * loading, we MUST clean up 'header' now. 19049689912eSchristos */ 19059689912eSchristos if (topheader_prev != NULL) { 19069689912eSchristos topheader_prev->next = newheader; 19079689912eSchristos } else { 19089689912eSchristos node->data = newheader; 19099689912eSchristos } 19109689912eSchristos newheader->next = topheader->next; 19119689912eSchristos maybe_update_recordsandsize(false, version, header, 19129689912eSchristos nodename->length); 19139689912eSchristos dns_slabheader_destroy(&header); 19149689912eSchristos } else { 19159689912eSchristos if (RESIGN(newheader)) { 19169689912eSchristos resigninsert(qpdb, newheader); 19179689912eSchristos resigndelete(qpdb, version, 19189689912eSchristos header DNS__DB_FLARG_PASS); 19199689912eSchristos } 19209689912eSchristos if (topheader_prev != NULL) { 19219689912eSchristos topheader_prev->next = newheader; 19229689912eSchristos } else { 19239689912eSchristos node->data = newheader; 19249689912eSchristos } 19259689912eSchristos newheader->next = topheader->next; 19269689912eSchristos newheader->down = topheader; 19279689912eSchristos topheader->next = newheader; 19289689912eSchristos node->dirty = true; 19299689912eSchristos if (changed != NULL) { 19309689912eSchristos changed->dirty = true; 19319689912eSchristos } 19329689912eSchristos maybe_update_recordsandsize(false, version, header, 19339689912eSchristos nodename->length); 19349689912eSchristos } 19359689912eSchristos } else { 19369689912eSchristos /* 19379689912eSchristos * No non-IGNORED rdatasets of the given type exist at 19389689912eSchristos * this node. 19399689912eSchristos * 19409689912eSchristos * If we're trying to delete the type, don't bother. 19419689912eSchristos */ 19429689912eSchristos if (NONEXISTENT(newheader)) { 19439689912eSchristos dns_slabheader_destroy(&newheader); 19449689912eSchristos return DNS_R_UNCHANGED; 19459689912eSchristos } 19469689912eSchristos 19479689912eSchristos if (RESIGN(newheader)) { 19489689912eSchristos resigninsert(qpdb, newheader); 19499689912eSchristos resigndelete(qpdb, version, header DNS__DB_FLARG_PASS); 19509689912eSchristos } 19519689912eSchristos 19529689912eSchristos if (topheader != NULL) { 19539689912eSchristos /* 19549689912eSchristos * We have a list of rdatasets of the given type, 19559689912eSchristos * but they're all marked IGNORE. We simply insert 19569689912eSchristos * the new rdataset at the head of the list. 19579689912eSchristos * 19589689912eSchristos * Ignored rdatasets cannot occur during loading, so 19599689912eSchristos * we INSIST on it. 19609689912eSchristos */ 19619689912eSchristos INSIST(!loading); 19629689912eSchristos INSIST(version->serial >= topheader->serial); 19639689912eSchristos if (topheader_prev != NULL) { 19649689912eSchristos topheader_prev->next = newheader; 19659689912eSchristos } else { 19669689912eSchristos node->data = newheader; 19679689912eSchristos } 19689689912eSchristos newheader->next = topheader->next; 19699689912eSchristos newheader->down = topheader; 19709689912eSchristos topheader->next = newheader; 19719689912eSchristos if (changed != NULL) { 19729689912eSchristos changed->dirty = true; 19739689912eSchristos } 19749689912eSchristos node->dirty = true; 19759689912eSchristos } else { 19769689912eSchristos /* 19779689912eSchristos * No rdatasets of the given type exist at the node. 19789689912eSchristos */ 19799689912eSchristos 19809689912eSchristos if (qpdb->maxtypepername > 0 && 19819689912eSchristos ntypes >= qpdb->maxtypepername) 19829689912eSchristos { 19839689912eSchristos dns_slabheader_destroy(&newheader); 19849689912eSchristos return DNS_R_TOOMANYRECORDS; 19859689912eSchristos } 19869689912eSchristos 19879689912eSchristos INSIST(newheader->down == NULL); 19889689912eSchristos 19899689912eSchristos if (prio_type(newheader->type)) { 19909689912eSchristos /* This is a priority type, prepend it */ 19919689912eSchristos newheader->next = node->data; 19929689912eSchristos node->data = newheader; 19939689912eSchristos } else if (prioheader != NULL) { 19949689912eSchristos /* Append after the priority headers */ 19959689912eSchristos newheader->next = prioheader->next; 19969689912eSchristos prioheader->next = newheader; 19979689912eSchristos } else { 19989689912eSchristos /* There were no priority headers */ 19999689912eSchristos newheader->next = node->data; 20009689912eSchristos node->data = newheader; 20019689912eSchristos } 20029689912eSchristos } 20039689912eSchristos } 20049689912eSchristos 20059689912eSchristos maybe_update_recordsandsize(true, version, newheader, nodename->length); 20069689912eSchristos 20079689912eSchristos /* 20089689912eSchristos * Check if the node now contains CNAME and other data. 20099689912eSchristos */ 20109689912eSchristos if (cname_and_other(node, version->serial)) { 20119689912eSchristos return DNS_R_CNAMEANDOTHER; 20129689912eSchristos } 20139689912eSchristos 20149689912eSchristos if (addedrdataset != NULL) { 20159689912eSchristos bindrdataset(qpdb, node, newheader, now, 20169689912eSchristos addedrdataset DNS__DB_FLARG_PASS); 20179689912eSchristos } 20189689912eSchristos 20199689912eSchristos return ISC_R_SUCCESS; 20209689912eSchristos } 20219689912eSchristos 20229689912eSchristos static void 20239689912eSchristos wildcardmagic(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name) { 20249689912eSchristos isc_result_t result; 20259689912eSchristos dns_name_t foundname; 20269689912eSchristos dns_offsets_t offsets; 20279689912eSchristos unsigned int n; 20289689912eSchristos qpznode_t *node = NULL; 20299689912eSchristos 20309689912eSchristos dns_name_init(&foundname, offsets); 20319689912eSchristos n = dns_name_countlabels(name); 20329689912eSchristos INSIST(n >= 2); 20339689912eSchristos n--; 20349689912eSchristos dns_name_getlabelsequence(name, 1, n, &foundname); 20359689912eSchristos 20369689912eSchristos /* insert an empty node, if needed, to hold the wildcard bit */ 20379689912eSchristos result = dns_qp_getname(qp, &foundname, (void **)&node, NULL); 20389689912eSchristos if (result != ISC_R_SUCCESS) { 20399689912eSchristos INSIST(node == NULL); 20409689912eSchristos node = new_qpznode(qpdb, &foundname); 20419689912eSchristos result = dns_qp_insert(qp, node, 0); 20429689912eSchristos INSIST(result == ISC_R_SUCCESS); 20439689912eSchristos qpznode_unref(node); 20449689912eSchristos } 20459689912eSchristos 20469689912eSchristos node->wild = true; 20479689912eSchristos } 20489689912eSchristos 20499689912eSchristos static void 20509689912eSchristos addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name) { 20519689912eSchristos dns_name_t foundname; 20529689912eSchristos dns_offsets_t offsets; 20539689912eSchristos unsigned int n, l, i; 20549689912eSchristos 20559689912eSchristos dns_name_init(&foundname, offsets); 20569689912eSchristos n = dns_name_countlabels(name); 20579689912eSchristos l = dns_name_countlabels(&qpdb->common.origin); 20589689912eSchristos i = l + 1; 20599689912eSchristos while (i < n) { 20609689912eSchristos dns_name_getlabelsequence(name, n - i, i, &foundname); 20619689912eSchristos if (dns_name_iswildcard(&foundname)) { 20629689912eSchristos wildcardmagic(qpdb, qp, &foundname); 20639689912eSchristos } 20649689912eSchristos 20659689912eSchristos i++; 20669689912eSchristos } 20679689912eSchristos } 20689689912eSchristos 20699689912eSchristos static isc_result_t 20709689912eSchristos loading_addrdataset(void *arg, const dns_name_t *name, 20719689912eSchristos dns_rdataset_t *rdataset DNS__DB_FLARG) { 20729689912eSchristos qpz_load_t *loadctx = arg; 20739689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db; 20749689912eSchristos qpznode_t *node = NULL; 20759689912eSchristos isc_result_t result = ISC_R_SUCCESS; 20769689912eSchristos isc_region_t region; 20779689912eSchristos dns_slabheader_t *newheader = NULL; 20789689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 20799689912eSchristos 20809689912eSchristos REQUIRE(rdataset->rdclass == qpdb->common.rdclass); 20819689912eSchristos 20829689912eSchristos /* 20839689912eSchristos * SOA records are only allowed at top of zone. 20849689912eSchristos */ 20859689912eSchristos if (rdataset->type == dns_rdatatype_soa && 20869689912eSchristos !dns_name_equal(name, &qpdb->common.origin)) 20879689912eSchristos { 20889689912eSchristos return DNS_R_NOTZONETOP; 20899689912eSchristos } 20909689912eSchristos 20919689912eSchristos if (rdataset->type != dns_rdatatype_nsec3 && 20929689912eSchristos rdataset->covers != dns_rdatatype_nsec3) 20939689912eSchristos { 20949689912eSchristos addwildcards(qpdb, loadctx->tree, name); 20959689912eSchristos } 20969689912eSchristos 20979689912eSchristos if (dns_name_iswildcard(name)) { 20989689912eSchristos if (rdataset->type == dns_rdatatype_ns) { 20999689912eSchristos /* 21009689912eSchristos * NS owners cannot legally be wild cards. 21019689912eSchristos */ 21029689912eSchristos return DNS_R_INVALIDNS; 21039689912eSchristos } 21049689912eSchristos 21059689912eSchristos if (rdataset->type == dns_rdatatype_nsec3) { 21069689912eSchristos /* 21079689912eSchristos * NSEC3 owners cannot legally be wild cards. 21089689912eSchristos */ 21099689912eSchristos return DNS_R_INVALIDNSEC3; 21109689912eSchristos } 21119689912eSchristos 21129689912eSchristos wildcardmagic(qpdb, loadctx->tree, name); 21139689912eSchristos } 21149689912eSchristos 21159689912eSchristos loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node); 21169689912eSchristos result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, 21179689912eSchristos ®ion, sizeof(dns_slabheader_t), 21189689912eSchristos qpdb->maxrrperset); 21199689912eSchristos if (result != ISC_R_SUCCESS) { 21209689912eSchristos if (result == DNS_R_TOOMANYRECORDS) { 21219689912eSchristos dns__db_logtoomanyrecords((dns_db_t *)qpdb, name, 21229689912eSchristos rdataset->type, "adding", 21239689912eSchristos qpdb->maxrrperset); 21249689912eSchristos } 21259689912eSchristos return result; 21269689912eSchristos } 21279689912eSchristos 21289689912eSchristos newheader = (dns_slabheader_t *)region.base; 21299689912eSchristos *newheader = (dns_slabheader_t){ 21309689912eSchristos .type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers), 21319689912eSchristos .ttl = rdataset->ttl + loadctx->now, 21329689912eSchristos .trust = rdataset->trust, 21339689912eSchristos .node = node, 21349689912eSchristos .serial = 1, 21359689912eSchristos .count = 1, 21369689912eSchristos }; 21379689912eSchristos 21389689912eSchristos dns_slabheader_reset(newheader, (dns_db_t *)qpdb, node); 21399689912eSchristos dns_slabheader_setownercase(newheader, name); 21409689912eSchristos 21419689912eSchristos if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { 21429689912eSchristos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); 21439689912eSchristos newheader->resign = 21449689912eSchristos (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 21459689912eSchristos 1); 21469689912eSchristos newheader->resign_lsb = rdataset->resign & 0x1; 21479689912eSchristos } 21489689912eSchristos 21499689912eSchristos NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 21509689912eSchristos result = add(qpdb, node, name, qpdb->current_version, newheader, 21519689912eSchristos DNS_DBADD_MERGE, true, NULL, 0 DNS__DB_FLARG_PASS); 21529689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 21539689912eSchristos 21549689912eSchristos if (result == ISC_R_SUCCESS && 21559689912eSchristos delegating_type(qpdb, node, rdataset->type)) 21569689912eSchristos { 21579689912eSchristos node->delegating = true; 21589689912eSchristos } else if (result == DNS_R_UNCHANGED) { 21599689912eSchristos result = ISC_R_SUCCESS; 21609689912eSchristos } 21619689912eSchristos 21629689912eSchristos return result; 21639689912eSchristos } 21649689912eSchristos 21659689912eSchristos static void 21669689912eSchristos loading_setup(void *arg) { 21679689912eSchristos qpz_load_t *loadctx = arg; 21689689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db; 21699689912eSchristos 21709689912eSchristos dns_qpmulti_write(qpdb->tree, &loadctx->tree); 21719689912eSchristos dns_qpmulti_write(qpdb->nsec, &loadctx->nsec); 21729689912eSchristos dns_qpmulti_write(qpdb->nsec3, &loadctx->nsec3); 21739689912eSchristos } 21749689912eSchristos 21759689912eSchristos static void 21769689912eSchristos loading_commit(void *arg) { 21779689912eSchristos qpz_load_t *loadctx = arg; 21789689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db; 21799689912eSchristos 21809689912eSchristos if (loadctx->tree != NULL) { 21819689912eSchristos dns_qp_compact(loadctx->tree, DNS_QPGC_MAYBE); 21829689912eSchristos dns_qpmulti_commit(qpdb->tree, &loadctx->tree); 21839689912eSchristos } 21849689912eSchristos if (loadctx->nsec != NULL) { 21859689912eSchristos dns_qp_compact(loadctx->nsec, DNS_QPGC_MAYBE); 21869689912eSchristos dns_qpmulti_commit(qpdb->nsec, &loadctx->nsec); 21879689912eSchristos } 21889689912eSchristos if (loadctx->nsec3 != NULL) { 21899689912eSchristos dns_qp_compact(loadctx->nsec3, DNS_QPGC_MAYBE); 21909689912eSchristos dns_qpmulti_commit(qpdb->nsec3, &loadctx->nsec3); 21919689912eSchristos } 21929689912eSchristos } 21939689912eSchristos 21949689912eSchristos static isc_result_t 21959689912eSchristos beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 21969689912eSchristos qpz_load_t *loadctx = NULL; 21979689912eSchristos qpzonedb_t *qpdb = NULL; 21989689912eSchristos qpdb = (qpzonedb_t *)db; 21999689912eSchristos 22009689912eSchristos REQUIRE(DNS_CALLBACK_VALID(callbacks)); 22019689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 22029689912eSchristos 22039689912eSchristos loadctx = isc_mem_get(qpdb->common.mctx, sizeof(*loadctx)); 22049689912eSchristos *loadctx = (qpz_load_t){ .db = db }; 22059689912eSchristos 22069689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 22079689912eSchristos 22089689912eSchristos REQUIRE((qpdb->attributes & (QPDB_ATTR_LOADED | QPDB_ATTR_LOADING)) == 22099689912eSchristos 0); 22109689912eSchristos qpdb->attributes |= QPDB_ATTR_LOADING; 22119689912eSchristos 22129689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 22139689912eSchristos 22149689912eSchristos callbacks->add = loading_addrdataset; 22159689912eSchristos callbacks->setup = loading_setup; 22169689912eSchristos callbacks->commit = loading_commit; 22179689912eSchristos callbacks->add_private = loadctx; 22189689912eSchristos 22199689912eSchristos return ISC_R_SUCCESS; 22209689912eSchristos } 22219689912eSchristos 22229689912eSchristos static isc_result_t 22239689912eSchristos endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 22249689912eSchristos qpz_load_t *loadctx = NULL; 22259689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 22269689912eSchristos 22279689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 22289689912eSchristos REQUIRE(DNS_CALLBACK_VALID(callbacks)); 22299689912eSchristos loadctx = callbacks->add_private; 22309689912eSchristos REQUIRE(loadctx != NULL); 22319689912eSchristos REQUIRE(loadctx->db == db); 22329689912eSchristos 22339689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 22349689912eSchristos 22359689912eSchristos REQUIRE((qpdb->attributes & QPDB_ATTR_LOADING) != 0); 22369689912eSchristos REQUIRE((qpdb->attributes & QPDB_ATTR_LOADED) == 0); 22379689912eSchristos 22389689912eSchristos qpdb->attributes &= ~QPDB_ATTR_LOADING; 22399689912eSchristos qpdb->attributes |= QPDB_ATTR_LOADED; 22409689912eSchristos 22419689912eSchristos if (qpdb->origin != NULL) { 22429689912eSchristos dns_dbversion_t *version = qpdb->current_version; 22439689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 22449689912eSchristos setsecure(db, version, qpdb->origin); 22459689912eSchristos } else { 22469689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 22479689912eSchristos } 22489689912eSchristos 22499689912eSchristos callbacks->add = NULL; 22509689912eSchristos callbacks->setup = NULL; 22519689912eSchristos callbacks->commit = NULL; 22529689912eSchristos callbacks->add_private = NULL; 22539689912eSchristos 22549689912eSchristos isc_mem_put(qpdb->common.mctx, loadctx, sizeof(*loadctx)); 22559689912eSchristos 22569689912eSchristos return ISC_R_SUCCESS; 22579689912eSchristos } 22589689912eSchristos 22599689912eSchristos static bool 22609689912eSchristos issecure(dns_db_t *db) { 22619689912eSchristos qpzonedb_t *qpdb = NULL; 22629689912eSchristos bool secure; 22639689912eSchristos 22649689912eSchristos qpdb = (qpzonedb_t *)db; 22659689912eSchristos 22669689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 22679689912eSchristos 22689689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 22699689912eSchristos secure = qpdb->current_version->secure; 22709689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 22719689912eSchristos 22729689912eSchristos return secure; 22739689912eSchristos } 22749689912eSchristos 22759689912eSchristos static isc_result_t 22769689912eSchristos getnsec3parameters(dns_db_t *db, dns_dbversion_t *dbversion, dns_hash_t *hash, 22779689912eSchristos uint8_t *flags, uint16_t *iterations, unsigned char *salt, 22789689912eSchristos size_t *salt_length) { 22799689912eSchristos qpzonedb_t *qpdb = NULL; 22809689912eSchristos isc_result_t result = ISC_R_NOTFOUND; 22819689912eSchristos qpz_version_t *version = dbversion; 22829689912eSchristos 22839689912eSchristos qpdb = (qpzonedb_t *)db; 22849689912eSchristos 22859689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 22869689912eSchristos INSIST(version == NULL || version->qpdb == qpdb); 22879689912eSchristos 22889689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 22899689912eSchristos if (version == NULL) { 22909689912eSchristos version = qpdb->current_version; 22919689912eSchristos } 22929689912eSchristos 22939689912eSchristos if (version->havensec3) { 22949689912eSchristos if (hash != NULL) { 22959689912eSchristos *hash = version->hash; 22969689912eSchristos } 22979689912eSchristos if (salt != NULL && salt_length != NULL) { 22989689912eSchristos REQUIRE(*salt_length >= version->salt_length); 22999689912eSchristos memmove(salt, version->salt, version->salt_length); 23009689912eSchristos } 23019689912eSchristos if (salt_length != NULL) { 23029689912eSchristos *salt_length = version->salt_length; 23039689912eSchristos } 23049689912eSchristos if (iterations != NULL) { 23059689912eSchristos *iterations = version->iterations; 23069689912eSchristos } 23079689912eSchristos if (flags != NULL) { 23089689912eSchristos *flags = version->flags; 23099689912eSchristos } 23109689912eSchristos result = ISC_R_SUCCESS; 23119689912eSchristos } 23129689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 23139689912eSchristos 23149689912eSchristos return result; 23159689912eSchristos } 23169689912eSchristos 23179689912eSchristos static isc_result_t 23189689912eSchristos getsize(dns_db_t *db, dns_dbversion_t *dbversion, uint64_t *records, 23199689912eSchristos uint64_t *xfrsize) { 23209689912eSchristos qpzonedb_t *qpdb = NULL; 23219689912eSchristos qpz_version_t *version = dbversion; 23229689912eSchristos isc_result_t result = ISC_R_SUCCESS; 23239689912eSchristos 23249689912eSchristos qpdb = (qpzonedb_t *)db; 23259689912eSchristos 23269689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 23279689912eSchristos INSIST(version == NULL || version->qpdb == qpdb); 23289689912eSchristos 23299689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 23309689912eSchristos if (version == NULL) { 23319689912eSchristos version = qpdb->current_version; 23329689912eSchristos } 23339689912eSchristos 23349689912eSchristos RWLOCK(&version->rwlock, isc_rwlocktype_read); 23359689912eSchristos SET_IF_NOT_NULL(records, version->records); 23369689912eSchristos 23379689912eSchristos SET_IF_NOT_NULL(xfrsize, version->xfrsize); 23389689912eSchristos RWUNLOCK(&version->rwlock, isc_rwlocktype_read); 23399689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 23409689912eSchristos 23419689912eSchristos return result; 23429689912eSchristos } 23439689912eSchristos 23449689912eSchristos static isc_result_t 23459689912eSchristos setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { 23469689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 23479689912eSchristos dns_slabheader_t *header = NULL, oldheader; 23489689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 23499689912eSchristos 23509689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 23519689912eSchristos REQUIRE(rdataset != NULL); 23529689912eSchristos REQUIRE(rdataset->methods == &dns_rdataslab_rdatasetmethods); 23539689912eSchristos 23549689912eSchristos header = dns_slabheader_fromrdataset(rdataset); 23559689912eSchristos 23569689912eSchristos NODE_WRLOCK(&qpdb->node_locks[HEADERNODE(header)->locknum].lock, 23579689912eSchristos &nlocktype); 23589689912eSchristos 23599689912eSchristos oldheader = *header; 23609689912eSchristos 23619689912eSchristos /* 23629689912eSchristos * Only break the heap invariant (by adjusting resign and resign_lsb) 23639689912eSchristos * if we are going to be restoring it by calling isc_heap_increased 23649689912eSchristos * or isc_heap_decreased. 23659689912eSchristos */ 23669689912eSchristos if (resign != 0) { 23679689912eSchristos header->resign = (isc_stdtime_t)(dns_time64_from32(resign) >> 23689689912eSchristos 1); 23699689912eSchristos header->resign_lsb = resign & 0x1; 23709689912eSchristos } 23719689912eSchristos if (header->heap_index != 0) { 23729689912eSchristos INSIST(RESIGN(header)); 23739689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 23749689912eSchristos if (resign == 0) { 23759689912eSchristos isc_heap_delete(qpdb->heap, header->heap_index); 23769689912eSchristos header->heap_index = 0; 23779689912eSchristos header->heap = NULL; 23789689912eSchristos } else if (resign_sooner(header, &oldheader)) { 23799689912eSchristos isc_heap_increased(qpdb->heap, header->heap_index); 23809689912eSchristos } else if (resign_sooner(&oldheader, header)) { 23819689912eSchristos isc_heap_decreased(qpdb->heap, header->heap_index); 23829689912eSchristos } 23839689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 23849689912eSchristos } else if (resign != 0) { 23859689912eSchristos DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_RESIGN); 23869689912eSchristos resigninsert(qpdb, header); 23879689912eSchristos } 23889689912eSchristos NODE_UNLOCK(&qpdb->node_locks[HEADERNODE(header)->locknum].lock, 23899689912eSchristos &nlocktype); 23909689912eSchristos return ISC_R_SUCCESS; 23919689912eSchristos } 23929689912eSchristos 23939689912eSchristos static isc_result_t 23949689912eSchristos getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *foundname, 23959689912eSchristos dns_typepair_t *typepair) { 23969689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 23979689912eSchristos dns_slabheader_t *header = NULL; 23989689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 23999689912eSchristos uint16_t locknum; 24009689912eSchristos isc_result_t result = ISC_R_NOTFOUND; 24019689912eSchristos 24029689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 24039689912eSchristos REQUIRE(resign != NULL); 24049689912eSchristos REQUIRE(foundname != NULL); 24059689912eSchristos REQUIRE(typepair != NULL); 24069689912eSchristos 24079689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 24089689912eSchristos header = isc_heap_element(qpdb->heap, 1); 24099689912eSchristos if (header == NULL) { 24109689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 24119689912eSchristos return ISC_R_NOTFOUND; 24129689912eSchristos } 24139689912eSchristos locknum = HEADERNODE(header)->locknum; 24149689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 24159689912eSchristos 24169689912eSchristos again: 24179689912eSchristos NODE_RDLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); 24189689912eSchristos 24199689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_read); 24209689912eSchristos header = isc_heap_element(qpdb->heap, 1); 24219689912eSchristos if (header != NULL && HEADERNODE(header)->locknum != locknum) { 24229689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 24239689912eSchristos NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); 24249689912eSchristos locknum = HEADERNODE(header)->locknum; 24259689912eSchristos goto again; 24269689912eSchristos } 24279689912eSchristos 24289689912eSchristos if (header != NULL) { 24299689912eSchristos *resign = RESIGN(header) 24309689912eSchristos ? (header->resign << 1) | header->resign_lsb 24319689912eSchristos : 0; 24329689912eSchristos dns_name_copy(&HEADERNODE(header)->name, foundname); 24339689912eSchristos *typepair = header->type; 24349689912eSchristos result = ISC_R_SUCCESS; 24359689912eSchristos } 24369689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_read); 24379689912eSchristos NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype); 24389689912eSchristos 24399689912eSchristos return result; 24409689912eSchristos } 24419689912eSchristos 24429689912eSchristos static isc_result_t 24439689912eSchristos setgluecachestats(dns_db_t *db, isc_stats_t *stats) { 24449689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 24459689912eSchristos 24469689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 24479689912eSchristos REQUIRE(!IS_STUB(qpdb)); 24489689912eSchristos REQUIRE(stats != NULL); 24499689912eSchristos 24509689912eSchristos isc_stats_attach(stats, &qpdb->gluecachestats); 24519689912eSchristos return ISC_R_SUCCESS; 24529689912eSchristos } 24539689912eSchristos 24549689912eSchristos static isc_result_t 24559689912eSchristos findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create, 24569689912eSchristos bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) { 24579689912eSchristos isc_result_t result; 24589689912eSchristos qpznode_t *node = NULL; 24599689912eSchristos dns_qpmulti_t *dbtree = nsec3 ? qpdb->nsec3 : qpdb->tree; 24609689912eSchristos dns_qpread_t qpr = { 0 }; 24619689912eSchristos dns_qp_t *qp = NULL; 24629689912eSchristos 24639689912eSchristos if (create) { 24649689912eSchristos dns_qpmulti_write(dbtree, &qp); 24659689912eSchristos } else { 24669689912eSchristos dns_qpmulti_query(dbtree, &qpr); 24679689912eSchristos qp = (dns_qp_t *)&qpr; 24689689912eSchristos } 24699689912eSchristos 24709689912eSchristos result = dns_qp_getname(qp, name, (void **)&node, NULL); 24719689912eSchristos if (result != ISC_R_SUCCESS) { 24729689912eSchristos if (!create) { 24739689912eSchristos dns_qpread_destroy(dbtree, &qpr); 24749689912eSchristos return result; 24759689912eSchristos } 24769689912eSchristos 24779689912eSchristos node = new_qpznode(qpdb, name); 24789689912eSchristos result = dns_qp_insert(qp, node, 0); 24799689912eSchristos qpznode_unref(node); 24809689912eSchristos 24819689912eSchristos if (result == ISC_R_SUCCESS) { 24829689912eSchristos if (nsec3) { 24839689912eSchristos node->nsec = DNS_DB_NSEC_NSEC3; 24849689912eSchristos } else { 24859689912eSchristos addwildcards(qpdb, qp, name); 24869689912eSchristos if (dns_name_iswildcard(name)) { 24879689912eSchristos wildcardmagic(qpdb, qp, name); 24889689912eSchristos } 24899689912eSchristos } 24909689912eSchristos } 24919689912eSchristos 24929689912eSchristos INSIST(node->nsec == DNS_DB_NSEC_NSEC3 || !nsec3); 24939689912eSchristos } 24949689912eSchristos 24959689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 24969689912eSchristos 24979689912eSchristos if (create) { 24989689912eSchristos dns_qp_compact(qp, DNS_QPGC_MAYBE); 24999689912eSchristos dns_qpmulti_commit(dbtree, &qp); 25009689912eSchristos } else { 25019689912eSchristos dns_qpread_destroy(dbtree, &qpr); 25029689912eSchristos } 25039689912eSchristos 25049689912eSchristos *nodep = (dns_dbnode_t *)node; 25059689912eSchristos 25069689912eSchristos return ISC_R_SUCCESS; 25079689912eSchristos } 25089689912eSchristos 25099689912eSchristos static isc_result_t 25109689912eSchristos findnode(dns_db_t *db, const dns_name_t *name, bool create, 25119689912eSchristos dns_dbnode_t **nodep DNS__DB_FLARG) { 25129689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 25139689912eSchristos 25149689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 25159689912eSchristos 25169689912eSchristos return findnodeintree(qpdb, name, create, false, 25179689912eSchristos nodep DNS__DB_FLARG_PASS); 25189689912eSchristos } 25199689912eSchristos 25209689912eSchristos static isc_result_t 25219689912eSchristos findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, 25229689912eSchristos dns_dbnode_t **nodep DNS__DB_FLARG) { 25239689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 25249689912eSchristos 25259689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 25269689912eSchristos 25279689912eSchristos return findnodeintree(qpdb, name, create, true, 25289689912eSchristos nodep DNS__DB_FLARG_PASS); 25299689912eSchristos } 25309689912eSchristos 25319689912eSchristos static bool 25329689912eSchristos matchparams(dns_slabheader_t *header, qpz_search_t *search) { 25339689912eSchristos dns_rdata_t rdata = DNS_RDATA_INIT; 25349689912eSchristos dns_rdata_nsec3_t nsec3; 25359689912eSchristos unsigned char *raw = NULL; 25369689912eSchristos unsigned int rdlen, count; 25379689912eSchristos isc_region_t region; 25389689912eSchristos isc_result_t result; 25399689912eSchristos 25409689912eSchristos REQUIRE(header->type == dns_rdatatype_nsec3); 25419689912eSchristos 25429689912eSchristos raw = (unsigned char *)header + sizeof(*header); 25439689912eSchristos count = raw[0] * 256 + raw[1]; /* count */ 25449689912eSchristos raw += DNS_RDATASET_COUNT + DNS_RDATASET_LENGTH; 25459689912eSchristos 25469689912eSchristos while (count-- > 0) { 25479689912eSchristos rdlen = raw[0] * 256 + raw[1]; 25489689912eSchristos raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; 25499689912eSchristos region.base = raw; 25509689912eSchristos region.length = rdlen; 25519689912eSchristos dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass, 25529689912eSchristos dns_rdatatype_nsec3, ®ion); 25539689912eSchristos raw += rdlen; 25549689912eSchristos result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 25559689912eSchristos INSIST(result == ISC_R_SUCCESS); 25569689912eSchristos if (nsec3.hash == search->version->hash && 25579689912eSchristos nsec3.iterations == search->version->iterations && 25589689912eSchristos nsec3.salt_length == search->version->salt_length && 25599689912eSchristos memcmp(nsec3.salt, search->version->salt, 25609689912eSchristos nsec3.salt_length) == 0) 25619689912eSchristos { 25629689912eSchristos return true; 25639689912eSchristos } 25649689912eSchristos dns_rdata_reset(&rdata); 25659689912eSchristos } 25669689912eSchristos return false; 25679689912eSchristos } 25689689912eSchristos 25699689912eSchristos static isc_result_t 25709689912eSchristos setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep, 25719689912eSchristos dns_name_t *foundname, dns_rdataset_t *rdataset, 25729689912eSchristos dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 25739689912eSchristos dns_name_t *zcname = NULL; 25749689912eSchristos dns_typepair_t type; 25759689912eSchristos qpznode_t *node = NULL; 25769689912eSchristos 25779689912eSchristos REQUIRE(search != NULL); 25789689912eSchristos REQUIRE(search->zonecut != NULL); 25799689912eSchristos REQUIRE(search->zonecut_header != NULL); 25809689912eSchristos 25819689912eSchristos /* 25829689912eSchristos * The caller MUST NOT be holding any node locks. 25839689912eSchristos */ 25849689912eSchristos 25859689912eSchristos node = search->zonecut; 25869689912eSchristos type = search->zonecut_header->type; 25879689912eSchristos 25889689912eSchristos /* 25899689912eSchristos * If we have to set foundname, we do it before anything else. 25909689912eSchristos * If we were to set foundname after we had set nodep or bound the 25919689912eSchristos * rdataset, then we'd have to undo that work if dns_name_copy() 25929689912eSchristos * failed. By setting foundname first, there's nothing to undo if 25939689912eSchristos * we have trouble. 25949689912eSchristos */ 25959689912eSchristos if (foundname != NULL && search->copy_name) { 25969689912eSchristos zcname = dns_fixedname_name(&search->zonecut_name); 25979689912eSchristos dns_name_copy(zcname, foundname); 25989689912eSchristos } 25999689912eSchristos if (nodep != NULL) { 26009689912eSchristos /* 26019689912eSchristos * Note that we don't have to increment the node's reference 26029689912eSchristos * count here because we're going to use the reference we 26039689912eSchristos * already have in the search block. 26049689912eSchristos */ 26059689912eSchristos *nodep = node; 26069689912eSchristos search->need_cleanup = false; 26079689912eSchristos } 26089689912eSchristos if (rdataset != NULL) { 26099689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 26109689912eSchristos NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), 26119689912eSchristos &nlocktype); 26129689912eSchristos bindrdataset(search->qpdb, node, search->zonecut_header, 26139689912eSchristos search->now, rdataset DNS__DB_FLARG_PASS); 26149689912eSchristos if (sigrdataset != NULL && search->zonecut_sigheader != NULL) { 26159689912eSchristos bindrdataset(search->qpdb, node, 26169689912eSchristos search->zonecut_sigheader, search->now, 26179689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 26189689912eSchristos } 26199689912eSchristos NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), 26209689912eSchristos &nlocktype); 26219689912eSchristos } 26229689912eSchristos 26239689912eSchristos if (type == dns_rdatatype_dname) { 26249689912eSchristos return DNS_R_DNAME; 26259689912eSchristos } 26269689912eSchristos return DNS_R_DELEGATION; 26279689912eSchristos } 26289689912eSchristos 26299689912eSchristos typedef enum { FORWARD, BACK } direction_t; 26309689912eSchristos 26319689912eSchristos /* 26329689912eSchristos * Step backwards or forwards through the database until we find a 26339689912eSchristos * node with data in it for the desired version. If 'nextname' is not NULL, 26349689912eSchristos * and we found a predecessor or successor, save the name we found in it. 26359689912eSchristos * Return true if we found a predecessor or successor. 26369689912eSchristos */ 26379689912eSchristos static bool 26389689912eSchristos step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction, 26399689912eSchristos dns_name_t *nextname) { 26409689912eSchristos dns_fixedname_t fnodename; 26419689912eSchristos dns_name_t *nodename = dns_fixedname_initname(&fnodename); 26429689912eSchristos qpzonedb_t *qpdb = NULL; 26439689912eSchristos qpznode_t *node = NULL; 26449689912eSchristos isc_result_t result = ISC_R_SUCCESS; 26459689912eSchristos dns_slabheader_t *header = NULL; 26469689912eSchristos 26479689912eSchristos qpdb = search->qpdb; 26489689912eSchristos 26499689912eSchristos result = dns_qpiter_current(it, nodename, (void **)&node, NULL); 26509689912eSchristos while (result == ISC_R_SUCCESS) { 26519689912eSchristos isc_rwlock_t *nodelock = &qpdb->node_locks[node->locknum].lock; 26529689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 26539689912eSchristos 26549689912eSchristos NODE_RDLOCK(nodelock, &nlocktype); 26559689912eSchristos for (header = node->data; header != NULL; header = header->next) 26569689912eSchristos { 26579689912eSchristos if (header->serial <= search->serial && 26589689912eSchristos !IGNORE(header) && !NONEXISTENT(header)) 26599689912eSchristos { 26609689912eSchristos break; 26619689912eSchristos } 26629689912eSchristos } 26639689912eSchristos NODE_UNLOCK(nodelock, &nlocktype); 26649689912eSchristos if (header != NULL) { 26659689912eSchristos break; 26669689912eSchristos } 26679689912eSchristos 26689689912eSchristos if (direction == FORWARD) { 26699689912eSchristos result = dns_qpiter_next(it, nodename, (void **)&node, 26709689912eSchristos NULL); 26719689912eSchristos } else { 26729689912eSchristos result = dns_qpiter_prev(it, nodename, (void **)&node, 26739689912eSchristos NULL); 26749689912eSchristos } 26759689912eSchristos }; 26769689912eSchristos if (result == ISC_R_SUCCESS) { 26779689912eSchristos if (nextname != NULL) { 26789689912eSchristos dns_name_copy(nodename, nextname); 26799689912eSchristos } 26809689912eSchristos return true; 26819689912eSchristos } 26829689912eSchristos 26839689912eSchristos return false; 26849689912eSchristos } 26859689912eSchristos 26869689912eSchristos static bool 26879689912eSchristos activeempty(qpz_search_t *search, dns_qpiter_t *it, const dns_name_t *current) { 26889689912eSchristos dns_fixedname_t fnext; 26899689912eSchristos dns_name_t *next = dns_fixedname_initname(&fnext); 26909689912eSchristos 26919689912eSchristos /* 26929689912eSchristos * The iterator is currently pointed at the predecessor 26939689912eSchristos * of the name we were searching for. Step the iterator 26949689912eSchristos * forward, then step() will continue forward until it 26959689912eSchristos * finds a node with active data. If that node is a 26969689912eSchristos * subdomain of the one we were looking for, then we're 26979689912eSchristos * at an active empty nonterminal node. 26989689912eSchristos */ 26999689912eSchristos isc_result_t result = dns_qpiter_next(it, NULL, NULL, NULL); 27009689912eSchristos if (result != ISC_R_SUCCESS) { 27019689912eSchristos /* An ENT at the end of the zone is impossible */ 27029689912eSchristos return false; 27039689912eSchristos } 27049689912eSchristos return step(search, it, FORWARD, next) && 27059689912eSchristos dns_name_issubdomain(next, current); 27069689912eSchristos } 27079689912eSchristos 27089689912eSchristos static bool 27099689912eSchristos wildcard_blocked(qpz_search_t *search, const dns_name_t *qname, 27109689912eSchristos dns_name_t *wname) { 27119689912eSchristos isc_result_t result; 27129689912eSchristos dns_fixedname_t fnext; 27139689912eSchristos dns_fixedname_t fprev; 27149689912eSchristos dns_name_t *next = NULL, *prev = NULL; 27159689912eSchristos dns_name_t name; 27169689912eSchristos dns_name_t rname; 27179689912eSchristos dns_name_t tname; 27189689912eSchristos dns_qpiter_t it; 27199689912eSchristos bool check_next = false; 27209689912eSchristos bool check_prev = false; 27219689912eSchristos unsigned int n; 27229689912eSchristos 27239689912eSchristos dns_name_init(&name, NULL); 27249689912eSchristos dns_name_init(&tname, NULL); 27259689912eSchristos dns_name_init(&rname, NULL); 27269689912eSchristos next = dns_fixedname_initname(&fnext); 27279689912eSchristos prev = dns_fixedname_initname(&fprev); 27289689912eSchristos 27299689912eSchristos /* 27309689912eSchristos * The qname seems to have matched a wildcard, but we 27319689912eSchristos * need to find out if there's an empty nonterminal node 27329689912eSchristos * between the wildcard level and the qname. 27339689912eSchristos * 27349689912eSchristos * search->iter should now be pointing at the predecessor 27359689912eSchristos * of the searched-for name. We are using a local copy of the 27369689912eSchristos * iterator so as not to change the state of search->iter. 27379689912eSchristos * step() will walk backward until we find a predecessor with 27389689912eSchristos * data. 27399689912eSchristos */ 27409689912eSchristos it = search->iter; 27419689912eSchristos check_prev = step(search, &it, BACK, prev); 27429689912eSchristos 27439689912eSchristos /* Now reset the iterator and look for a successor with data. */ 27449689912eSchristos it = search->iter; 27459689912eSchristos result = dns_qpiter_next(&it, NULL, NULL, NULL); 27469689912eSchristos if (result == ISC_R_SUCCESS) { 27479689912eSchristos check_next = step(search, &it, FORWARD, next); 27489689912eSchristos } 27499689912eSchristos 27509689912eSchristos if (!check_prev && !check_next) { 27519689912eSchristos /* No predecessor or successor was found at all? */ 27529689912eSchristos return false; 27539689912eSchristos } 27549689912eSchristos 27559689912eSchristos dns_name_clone(qname, &rname); 27569689912eSchristos 27579689912eSchristos /* 27589689912eSchristos * Remove the wildcard label to find the terminal name. 27599689912eSchristos */ 27609689912eSchristos n = dns_name_countlabels(wname); 27619689912eSchristos dns_name_getlabelsequence(wname, 1, n - 1, &tname); 27629689912eSchristos 27639689912eSchristos do { 27649689912eSchristos if ((check_prev && dns_name_issubdomain(prev, &rname)) || 27659689912eSchristos (check_next && dns_name_issubdomain(next, &rname))) 27669689912eSchristos { 27679689912eSchristos return true; 27689689912eSchristos } 27699689912eSchristos 27709689912eSchristos /* 27719689912eSchristos * Remove the leftmost label from the qname and check again. 27729689912eSchristos */ 27739689912eSchristos n = dns_name_countlabels(&rname); 27749689912eSchristos dns_name_getlabelsequence(&rname, 1, n - 1, &rname); 27759689912eSchristos } while (!dns_name_equal(&rname, &tname)); 27769689912eSchristos 27779689912eSchristos return false; 27789689912eSchristos } 27799689912eSchristos 27809689912eSchristos static isc_result_t 27819689912eSchristos find_wildcard(qpz_search_t *search, qpznode_t **nodep, 27829689912eSchristos const dns_name_t *qname) { 27839689912eSchristos dns_slabheader_t *header = NULL; 27849689912eSchristos isc_result_t result = ISC_R_NOTFOUND; 27859689912eSchristos qpzonedb_t *qpdb = search->qpdb; 27869689912eSchristos 27879689912eSchristos /* 27889689912eSchristos * Examine each ancestor level. If the level's wild bit 27899689912eSchristos * is set, then construct the corresponding wildcard name and 27909689912eSchristos * search for it. If the wildcard node exists, and is active in 27919689912eSchristos * this version, we're done. If not, then we next check to see 27929689912eSchristos * if the ancestor is active in this version. If so, then there 27939689912eSchristos * can be no possible wildcard match and again we're done. If not, 27949689912eSchristos * continue the search. 27959689912eSchristos */ 27969689912eSchristos for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { 27979689912eSchristos qpznode_t *node = NULL; 27989689912eSchristos isc_rwlock_t *lock = NULL; 27999689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 28009689912eSchristos bool wild, active; 28019689912eSchristos 28029689912eSchristos dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL); 28039689912eSchristos 28049689912eSchristos lock = &qpdb->node_locks[node->locknum].lock; 28059689912eSchristos NODE_RDLOCK(lock, &nlocktype); 28069689912eSchristos /* 28079689912eSchristos * First we try to figure out if this node is active in 28089689912eSchristos * the search's version. We do this now, even though we 28099689912eSchristos * may not need the information, because it simplifies the 28109689912eSchristos * locking and code flow. 28119689912eSchristos */ 28129689912eSchristos for (header = node->data; header != NULL; header = header->next) 28139689912eSchristos { 28149689912eSchristos if (header->serial <= search->serial && 28159689912eSchristos !IGNORE(header) && !NONEXISTENT(header)) 28169689912eSchristos { 28179689912eSchristos break; 28189689912eSchristos } 28199689912eSchristos } 28209689912eSchristos 28219689912eSchristos active = (header != NULL); 28229689912eSchristos wild = node->wild; 28239689912eSchristos NODE_UNLOCK(lock, &nlocktype); 28249689912eSchristos 28259689912eSchristos if (wild) { 28269689912eSchristos qpznode_t *wnode = NULL; 28279689912eSchristos dns_fixedname_t fwname; 28289689912eSchristos dns_name_t *wname = dns_fixedname_initname(&fwname); 28299689912eSchristos dns_qpiter_t wit; 28309689912eSchristos 28319689912eSchristos /* 28329689912eSchristos * Construct the wildcard name for this level. 28339689912eSchristos */ 28349689912eSchristos result = dns_name_concatenate(dns_wildcardname, 28359689912eSchristos &node->name, wname, NULL); 28369689912eSchristos if (result != ISC_R_SUCCESS) { 28379689912eSchristos break; 28389689912eSchristos } 28399689912eSchristos 28409689912eSchristos result = dns_qp_lookup(&search->qpr, wname, NULL, &wit, 28419689912eSchristos NULL, (void **)&wnode, NULL); 28429689912eSchristos if (result == ISC_R_SUCCESS) { 28439689912eSchristos /* 28449689912eSchristos * We have found the wildcard node. If it 28459689912eSchristos * is active in the search's version, we're 28469689912eSchristos * done. 28479689912eSchristos */ 28489689912eSchristos lock = &qpdb->node_locks[wnode->locknum].lock; 28499689912eSchristos NODE_RDLOCK(lock, &nlocktype); 28509689912eSchristos for (header = wnode->data; header != NULL; 28519689912eSchristos header = header->next) 28529689912eSchristos { 28539689912eSchristos if (header->serial <= search->serial && 28549689912eSchristos !IGNORE(header) && 28559689912eSchristos !NONEXISTENT(header)) 28569689912eSchristos { 28579689912eSchristos break; 28589689912eSchristos } 28599689912eSchristos } 28609689912eSchristos NODE_UNLOCK(lock, &nlocktype); 28619689912eSchristos if (header != NULL || 28629689912eSchristos activeempty(search, &wit, wname)) 28639689912eSchristos { 28649689912eSchristos if (wildcard_blocked(search, qname, 28659689912eSchristos wname)) 28669689912eSchristos { 28679689912eSchristos return ISC_R_NOTFOUND; 28689689912eSchristos } 28699689912eSchristos 28709689912eSchristos /* 28719689912eSchristos * The wildcard node is active! 28729689912eSchristos * 28739689912eSchristos * Note: result is still ISC_R_SUCCESS 28749689912eSchristos * so we don't have to set it. 28759689912eSchristos */ 28769689912eSchristos *nodep = wnode; 28779689912eSchristos break; 28789689912eSchristos } 28799689912eSchristos } else if (result != ISC_R_NOTFOUND && 28809689912eSchristos result != DNS_R_PARTIALMATCH) 28819689912eSchristos { 28829689912eSchristos /* 28839689912eSchristos * An error has occurred. Bail out. 28849689912eSchristos */ 28859689912eSchristos break; 28869689912eSchristos } 28879689912eSchristos } 28889689912eSchristos 28899689912eSchristos if (active) { 28909689912eSchristos /* 28919689912eSchristos * The level node is active. Any wildcarding 28929689912eSchristos * present at higher levels has no 28939689912eSchristos * effect and we're done. 28949689912eSchristos */ 28959689912eSchristos result = ISC_R_NOTFOUND; 28969689912eSchristos break; 28979689912eSchristos } 28989689912eSchristos } 28999689912eSchristos 29009689912eSchristos return result; 29019689912eSchristos } 29029689912eSchristos 29039689912eSchristos /* 29049689912eSchristos * Find node of the NSEC/NSEC3 record that is 'name'. 29059689912eSchristos */ 29069689912eSchristos static isc_result_t 29079689912eSchristos previous_closest_nsec(dns_rdatatype_t type, qpz_search_t *search, 29089689912eSchristos dns_name_t *name, qpznode_t **nodep, dns_qpiter_t *nit, 29099689912eSchristos bool *firstp) { 29109689912eSchristos isc_result_t result; 29119689912eSchristos dns_qpread_t qpr; 29129689912eSchristos 29139689912eSchristos REQUIRE(nodep != NULL && *nodep == NULL); 29149689912eSchristos REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL); 29159689912eSchristos 29169689912eSchristos if (type == dns_rdatatype_nsec3) { 29179689912eSchristos result = dns_qpiter_prev(&search->iter, name, (void **)nodep, 29189689912eSchristos NULL); 29199689912eSchristos return result; 29209689912eSchristos } 29219689912eSchristos 29229689912eSchristos dns_qpmulti_query(search->qpdb->nsec, &qpr); 29239689912eSchristos 29249689912eSchristos for (;;) { 29259689912eSchristos if (*firstp) { 29269689912eSchristos /* 29279689912eSchristos * Construct the name of the second node to check. 29289689912eSchristos * It is the first node sought in the NSEC tree. 29299689912eSchristos */ 29309689912eSchristos *firstp = false; 29319689912eSchristos result = dns_qp_lookup(&qpr, name, NULL, nit, NULL, 29329689912eSchristos NULL, NULL); 29339689912eSchristos INSIST(result != ISC_R_NOTFOUND); 29349689912eSchristos if (result == ISC_R_SUCCESS) { 29359689912eSchristos /* 29369689912eSchristos * Since this was the first loop, finding the 29379689912eSchristos * name in the NSEC tree implies that the first 29389689912eSchristos * node checked in the main tree had an 29399689912eSchristos * unacceptable NSEC record. 29409689912eSchristos * Try the previous node in the NSEC tree. 29419689912eSchristos */ 29429689912eSchristos result = dns_qpiter_prev(nit, name, NULL, NULL); 29439689912eSchristos } else if (result == DNS_R_PARTIALMATCH) { 29449689912eSchristos /* 29459689912eSchristos * The iterator is already where we want it. 29469689912eSchristos */ 29479689912eSchristos dns_qpiter_current(nit, name, NULL, NULL); 29489689912eSchristos result = ISC_R_SUCCESS; 29499689912eSchristos } 29509689912eSchristos } else { 29519689912eSchristos /* 29529689912eSchristos * This is a second or later trip through the auxiliary 29539689912eSchristos * tree for the name of a third or earlier NSEC node in 29549689912eSchristos * the main tree. Previous trips through the NSEC tree 29559689912eSchristos * must have found nodes in the main tree with NSEC 29569689912eSchristos * records. Perhaps they lacked signature records. 29579689912eSchristos */ 29589689912eSchristos result = dns_qpiter_prev(nit, name, NULL, NULL); 29599689912eSchristos } 29609689912eSchristos if (result != ISC_R_SUCCESS) { 29619689912eSchristos break; 29629689912eSchristos } 29639689912eSchristos 29649689912eSchristos *nodep = NULL; 29659689912eSchristos result = dns_qp_lookup(&search->qpr, name, NULL, &search->iter, 29669689912eSchristos &search->chain, (void **)nodep, NULL); 29679689912eSchristos if (result == ISC_R_SUCCESS) { 29689689912eSchristos break; 29699689912eSchristos } 29709689912eSchristos 29719689912eSchristos /* 29729689912eSchristos * There should always be a node in the main tree with the 29739689912eSchristos * same name as the node in the auxiliary NSEC tree, except for 29749689912eSchristos * nodes in the auxiliary tree that are awaiting deletion. 29759689912eSchristos */ 29769689912eSchristos if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) { 29779689912eSchristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 29789689912eSchristos DNS_LOGMODULE_DB, ISC_LOG_ERROR, 29799689912eSchristos "previous_closest_nsec(): %s", 29809689912eSchristos isc_result_totext(result)); 29819689912eSchristos result = DNS_R_BADDB; 29829689912eSchristos break; 29839689912eSchristos } 29849689912eSchristos } 29859689912eSchristos 29869689912eSchristos dns_qpread_destroy(search->qpdb->nsec, &qpr); 29879689912eSchristos return result; 29889689912eSchristos } 29899689912eSchristos 29909689912eSchristos /* 29919689912eSchristos * Find the NSEC/NSEC3 which is or before the current point on the 29929689912eSchristos * search chain. For NSEC3 records only NSEC3 records that match the 29939689912eSchristos * current NSEC3PARAM record are considered. 29949689912eSchristos */ 29959689912eSchristos static isc_result_t 29969689912eSchristos find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep, 29979689912eSchristos dns_name_t *foundname, dns_rdataset_t *rdataset, 29989689912eSchristos dns_rdataset_t *sigrdataset, bool nsec3, 29999689912eSchristos bool secure DNS__DB_FLARG) { 30009689912eSchristos qpznode_t *node = NULL, *prevnode = NULL; 30019689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 30029689912eSchristos dns_qpiter_t nseciter; 30039689912eSchristos bool empty_node; 30049689912eSchristos isc_result_t result; 30059689912eSchristos dns_fixedname_t fname; 30069689912eSchristos dns_name_t *name = dns_fixedname_initname(&fname); 30079689912eSchristos dns_rdatatype_t type = dns_rdatatype_nsec; 30089689912eSchristos dns_typepair_t sigtype = DNS_SIGTYPE(dns_rdatatype_nsec); 30099689912eSchristos bool wraps = false; 30109689912eSchristos bool first = true; 30119689912eSchristos bool need_sig = secure; 30129689912eSchristos 30139689912eSchristos if (nsec3) { 30149689912eSchristos type = dns_rdatatype_nsec3; 30159689912eSchristos sigtype = DNS_SIGTYPE(dns_rdatatype_nsec3); 30169689912eSchristos wraps = true; 30179689912eSchristos } 30189689912eSchristos 30199689912eSchristos /* 30209689912eSchristos * Use the auxiliary tree only starting with the second node in the 30219689912eSchristos * hope that the original node will be right much of the time. 30229689912eSchristos */ 30239689912eSchristos result = dns_qpiter_current(&search->iter, name, (void **)&node, NULL); 30249689912eSchristos if (result != ISC_R_SUCCESS) { 30259689912eSchristos return result; 30269689912eSchristos } 30279689912eSchristos again: 30289689912eSchristos do { 30299689912eSchristos dns_slabheader_t *found = NULL, *foundsig = NULL; 30309689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 30319689912eSchristos NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), 30329689912eSchristos &nlocktype); 30339689912eSchristos empty_node = true; 30349689912eSchristos for (header = node->data; header != NULL; header = header_next) 30359689912eSchristos { 30369689912eSchristos header_next = header->next; 30379689912eSchristos /* 30389689912eSchristos * Look for an active, extant NSEC or RRSIG NSEC. 30399689912eSchristos */ 30409689912eSchristos do { 30419689912eSchristos if (header->serial <= search->serial && 30429689912eSchristos !IGNORE(header)) 30439689912eSchristos { 30449689912eSchristos if (NONEXISTENT(header)) { 30459689912eSchristos header = NULL; 30469689912eSchristos } 30479689912eSchristos break; 30489689912eSchristos } else { 30499689912eSchristos header = header->down; 30509689912eSchristos } 30519689912eSchristos } while (header != NULL); 30529689912eSchristos if (header != NULL) { 30539689912eSchristos /* 30549689912eSchristos * We now know that there is at least one 30559689912eSchristos * active rdataset at this node. 30569689912eSchristos */ 30579689912eSchristos empty_node = false; 30589689912eSchristos if (header->type == type) { 30599689912eSchristos found = header; 30609689912eSchristos if (foundsig != NULL) { 30619689912eSchristos break; 30629689912eSchristos } 30639689912eSchristos } else if (header->type == sigtype) { 30649689912eSchristos foundsig = header; 30659689912eSchristos if (found != NULL) { 30669689912eSchristos break; 30679689912eSchristos } 30689689912eSchristos } 30699689912eSchristos } 30709689912eSchristos } 30719689912eSchristos if (!empty_node) { 30729689912eSchristos if (found != NULL && search->version->havensec3 && 30739689912eSchristos found->type == dns_rdatatype_nsec3 && 30749689912eSchristos !matchparams(found, search)) 30759689912eSchristos { 30769689912eSchristos empty_node = true; 30779689912eSchristos found = NULL; 30789689912eSchristos foundsig = NULL; 30799689912eSchristos result = previous_closest_nsec(type, search, 30809689912eSchristos name, &prevnode, 30819689912eSchristos NULL, NULL); 30829689912eSchristos } else if (found != NULL && 30839689912eSchristos (foundsig != NULL || !need_sig)) 30849689912eSchristos { 30859689912eSchristos /* 30869689912eSchristos * We've found the right NSEC/NSEC3 record. 30879689912eSchristos * 30889689912eSchristos * Note: for this to really be the right 30899689912eSchristos * NSEC record, it's essential that the NSEC 30909689912eSchristos * records of any nodes obscured by a zone 30919689912eSchristos * cut have been removed; we assume this is 30929689912eSchristos * the case. 30939689912eSchristos */ 30949689912eSchristos dns_name_copy(name, foundname); 30959689912eSchristos if (nodep != NULL) { 30969689912eSchristos newref(search->qpdb, 30979689912eSchristos node DNS__DB_FLARG_PASS); 30989689912eSchristos *nodep = node; 30999689912eSchristos } 31009689912eSchristos bindrdataset(search->qpdb, node, found, 31019689912eSchristos search->now, 31029689912eSchristos rdataset DNS__DB_FLARG_PASS); 31039689912eSchristos if (foundsig != NULL) { 31049689912eSchristos bindrdataset( 31059689912eSchristos search->qpdb, node, foundsig, 31069689912eSchristos search->now, 31079689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 31089689912eSchristos } 31099689912eSchristos } else if (found == NULL && foundsig == NULL) { 31109689912eSchristos /* 31119689912eSchristos * This node is active, but has no NSEC or 31129689912eSchristos * RRSIG NSEC. That means it's glue or 31139689912eSchristos * other obscured zone data that isn't 31149689912eSchristos * relevant for our search. Treat the 31159689912eSchristos * node as if it were empty and keep looking. 31169689912eSchristos */ 31179689912eSchristos empty_node = true; 31189689912eSchristos result = previous_closest_nsec( 31199689912eSchristos type, search, name, &prevnode, 31209689912eSchristos &nseciter, &first); 31219689912eSchristos } else { 31229689912eSchristos /* 31239689912eSchristos * We found an active node, but either the 31249689912eSchristos * NSEC or the RRSIG NSEC is missing. This 31259689912eSchristos * shouldn't happen. 31269689912eSchristos */ 31279689912eSchristos result = DNS_R_BADDB; 31289689912eSchristos } 31299689912eSchristos } else { 31309689912eSchristos /* 31319689912eSchristos * This node isn't active. We've got to keep 31329689912eSchristos * looking. 31339689912eSchristos */ 31349689912eSchristos result = previous_closest_nsec(type, search, name, 31359689912eSchristos &prevnode, &nseciter, 31369689912eSchristos &first); 31379689912eSchristos } 31389689912eSchristos NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), 31399689912eSchristos &nlocktype); 31409689912eSchristos node = prevnode; 31419689912eSchristos prevnode = NULL; 31429689912eSchristos } while (empty_node && result == ISC_R_SUCCESS); 31439689912eSchristos 31449689912eSchristos if (result == ISC_R_NOMORE && wraps) { 31459689912eSchristos result = dns_qpiter_prev(&search->iter, name, (void **)&node, 31469689912eSchristos NULL); 31479689912eSchristos if (result == ISC_R_SUCCESS) { 31489689912eSchristos wraps = false; 31499689912eSchristos goto again; 31509689912eSchristos } 31519689912eSchristos } 31529689912eSchristos 31539689912eSchristos /* 31549689912eSchristos * If the result is ISC_R_NOMORE, then we got to the beginning of 31559689912eSchristos * the database and didn't find a NSEC record. This shouldn't 31569689912eSchristos * happen. 31579689912eSchristos */ 31589689912eSchristos if (result == ISC_R_NOMORE) { 31599689912eSchristos result = DNS_R_BADDB; 31609689912eSchristos } 31619689912eSchristos 31629689912eSchristos return result; 31639689912eSchristos } 31649689912eSchristos 31659689912eSchristos static isc_result_t 31669689912eSchristos check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { 31679689912eSchristos qpz_search_t *search = arg; 31689689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 31699689912eSchristos dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL; 31709689912eSchristos dns_slabheader_t *ns_header = NULL; 31719689912eSchristos dns_slabheader_t *found = NULL; 31729689912eSchristos isc_result_t result = DNS_R_CONTINUE; 31739689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 31749689912eSchristos 31759689912eSchristos NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock), 31769689912eSchristos &nlocktype); 31779689912eSchristos 31789689912eSchristos /* 31799689912eSchristos * Look for an NS or DNAME rdataset active in our version. 31809689912eSchristos */ 31819689912eSchristos for (header = node->data; header != NULL; header = header_next) { 31829689912eSchristos header_next = header->next; 31839689912eSchristos if (header->type == dns_rdatatype_ns || 31849689912eSchristos header->type == dns_rdatatype_dname || 31859689912eSchristos header->type == DNS_SIGTYPE(dns_rdatatype_dname)) 31869689912eSchristos { 31879689912eSchristos do { 31889689912eSchristos if (header->serial <= search->serial && 31899689912eSchristos !IGNORE(header)) 31909689912eSchristos { 31919689912eSchristos if (NONEXISTENT(header)) { 31929689912eSchristos header = NULL; 31939689912eSchristos } 31949689912eSchristos break; 31959689912eSchristos } else { 31969689912eSchristos header = header->down; 31979689912eSchristos } 31989689912eSchristos } while (header != NULL); 31999689912eSchristos if (header != NULL) { 32009689912eSchristos if (header->type == dns_rdatatype_dname) { 32019689912eSchristos dname_header = header; 32029689912eSchristos } else if (header->type == 32039689912eSchristos DNS_SIGTYPE(dns_rdatatype_dname)) 32049689912eSchristos { 32059689912eSchristos sigdname_header = header; 32069689912eSchristos } else if (node != search->qpdb->origin || 32079689912eSchristos IS_STUB(search->qpdb)) 32089689912eSchristos { 32099689912eSchristos /* 32109689912eSchristos * We've found an NS rdataset that 32119689912eSchristos * isn't at the origin node. 32129689912eSchristos */ 32139689912eSchristos ns_header = header; 32149689912eSchristos } 32159689912eSchristos } 32169689912eSchristos } 32179689912eSchristos } 32189689912eSchristos 32199689912eSchristos /* 32209689912eSchristos * Did we find anything? 32219689912eSchristos */ 32229689912eSchristos if (!IS_STUB(search->qpdb) && ns_header != NULL) { 32239689912eSchristos /* 32249689912eSchristos * Note that NS has precedence over DNAME if both exist 32259689912eSchristos * in a zone. Otherwise DNAME take precedence over NS. 32269689912eSchristos */ 32279689912eSchristos found = ns_header; 32289689912eSchristos search->zonecut_sigheader = NULL; 32299689912eSchristos } else if (dname_header != NULL) { 32309689912eSchristos found = dname_header; 32319689912eSchristos search->zonecut_sigheader = sigdname_header; 32329689912eSchristos } else if (ns_header != NULL) { 32339689912eSchristos found = ns_header; 32349689912eSchristos search->zonecut_sigheader = NULL; 32359689912eSchristos } 32369689912eSchristos 32379689912eSchristos if (found != NULL) { 32389689912eSchristos /* 32399689912eSchristos * We increment the reference count on node to ensure that 32409689912eSchristos * search->zonecut_header will still be valid later. 32419689912eSchristos */ 32429689912eSchristos newref(search->qpdb, node DNS__DB_FLARG_PASS); 32439689912eSchristos search->zonecut = node; 32449689912eSchristos search->zonecut_header = found; 32459689912eSchristos search->need_cleanup = true; 32469689912eSchristos /* 32479689912eSchristos * Since we've found a zonecut, anything beneath it is 32489689912eSchristos * glue and is not subject to wildcard matching, so we 32499689912eSchristos * may clear search->wild. 32509689912eSchristos */ 32519689912eSchristos search->wild = false; 32529689912eSchristos if ((search->options & DNS_DBFIND_GLUEOK) == 0) { 32539689912eSchristos /* 32549689912eSchristos * If the caller does not want to find glue, then 32559689912eSchristos * this is the best answer and the search should 32569689912eSchristos * stop now. 32579689912eSchristos */ 32589689912eSchristos result = DNS_R_PARTIALMATCH; 32599689912eSchristos } else { 32609689912eSchristos dns_name_t *zcname = NULL; 32619689912eSchristos 32629689912eSchristos /* 32639689912eSchristos * The search will continue beneath the zone cut. 32649689912eSchristos * This may or may not be the best match. In case it 32659689912eSchristos * is, we need to remember the node name. 32669689912eSchristos */ 32679689912eSchristos zcname = dns_fixedname_name(&search->zonecut_name); 32689689912eSchristos dns_name_copy(&node->name, zcname); 32699689912eSchristos search->copy_name = true; 32709689912eSchristos } 32719689912eSchristos } else { 32729689912eSchristos /* 32739689912eSchristos * There is no zonecut at this node which is active in this 32749689912eSchristos * version. 32759689912eSchristos * 32769689912eSchristos * If this is a "wild" node and the caller hasn't disabled 32779689912eSchristos * wildcard matching, remember that we've seen a wild node 32789689912eSchristos * in case we need to go searching for wildcard matches 32799689912eSchristos * later on. 32809689912eSchristos */ 32819689912eSchristos if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0) { 32829689912eSchristos search->wild = true; 32839689912eSchristos } 32849689912eSchristos } 32859689912eSchristos 32869689912eSchristos NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock), 32879689912eSchristos &nlocktype); 32889689912eSchristos 32899689912eSchristos return result; 32909689912eSchristos } 32919689912eSchristos 32929689912eSchristos static isc_result_t 32939689912eSchristos find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, 32949689912eSchristos dns_rdatatype_t type, unsigned int options, 32959689912eSchristos isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep, 32969689912eSchristos dns_name_t *foundname, dns_rdataset_t *rdataset, 32979689912eSchristos dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 32989689912eSchristos isc_result_t result; 32999689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 33009689912eSchristos qpznode_t *node = NULL; 33019689912eSchristos qpz_search_t search; 33029689912eSchristos bool cname_ok = true, close_version = false; 33039689912eSchristos bool maybe_zonecut = false, at_zonecut = false; 33049689912eSchristos bool wild = false, empty_node = false; 33059689912eSchristos bool nsec3 = false; 33069689912eSchristos dns_slabheader_t *header = NULL, *header_next = NULL; 33079689912eSchristos dns_slabheader_t *found = NULL, *nsecheader = NULL; 33089689912eSchristos dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL; 33099689912eSchristos dns_typepair_t sigtype; 33109689912eSchristos bool active; 33119689912eSchristos isc_rwlock_t *lock = NULL; 33129689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 33139689912eSchristos 33149689912eSchristos REQUIRE(VALID_QPZONE((qpzonedb_t *)db)); 33159689912eSchristos INSIST(version == NULL || 33169689912eSchristos ((qpz_version_t *)version)->qpdb == (qpzonedb_t *)db); 33179689912eSchristos 33189689912eSchristos /* 33199689912eSchristos * If the caller didn't supply a version, attach to the current 33209689912eSchristos * version. 33219689912eSchristos */ 33229689912eSchristos if (version == NULL) { 33239689912eSchristos currentversion(db, &version); 33249689912eSchristos close_version = true; 33259689912eSchristos } 33269689912eSchristos 33279689912eSchristos search = (qpz_search_t){ 33289689912eSchristos .qpdb = (qpzonedb_t *)db, 33299689912eSchristos .version = version, 33309689912eSchristos .serial = ((qpz_version_t *)version)->serial, 33319689912eSchristos .options = options, 33329689912eSchristos }; 33339689912eSchristos dns_fixedname_init(&search.zonecut_name); 33349689912eSchristos 33359689912eSchristos if ((options & DNS_DBFIND_FORCENSEC3) != 0) { 33369689912eSchristos dns_qpmulti_query(qpdb->nsec3, &search.qpr); 33379689912eSchristos nsec3 = true; 33389689912eSchristos } else { 33399689912eSchristos dns_qpmulti_query(qpdb->tree, &search.qpr); 33409689912eSchristos } 33419689912eSchristos 33429689912eSchristos /* 33439689912eSchristos * Search down from the root of the tree. 33449689912eSchristos */ 33459689912eSchristos result = dns_qp_lookup(&search.qpr, name, NULL, &search.iter, 33469689912eSchristos &search.chain, (void **)&node, NULL); 33479689912eSchristos if (result != ISC_R_NOTFOUND) { 33489689912eSchristos dns_name_copy(&node->name, foundname); 33499689912eSchristos } 33509689912eSchristos 33519689912eSchristos /* 33529689912eSchristos * Check the QP chain to see if there's a node above us with a 33539689912eSchristos * active DNAME or NS rdatasets. 33549689912eSchristos * 33559689912eSchristos * We're only interested in nodes above QNAME, so if the result 33569689912eSchristos * was success, then we skip the last item in the chain. 33579689912eSchristos */ 33589689912eSchristos unsigned int clen = dns_qpchain_length(&search.chain); 33599689912eSchristos if (result == ISC_R_SUCCESS) { 33609689912eSchristos clen--; 33619689912eSchristos } 33629689912eSchristos for (unsigned int i = 0; i < clen && search.zonecut == NULL; i++) { 33639689912eSchristos qpznode_t *n = NULL; 33649689912eSchristos isc_result_t tresult; 33659689912eSchristos 33669689912eSchristos dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL); 33679689912eSchristos tresult = check_zonecut(n, &search DNS__DB_FLARG_PASS); 33689689912eSchristos if (tresult != DNS_R_CONTINUE) { 33699689912eSchristos result = tresult; 33709689912eSchristos search.chain.len = i - 1; 33719689912eSchristos node = n; 33729689912eSchristos if (foundname != NULL) { 33739689912eSchristos dns_name_copy(&node->name, foundname); 33749689912eSchristos } 33759689912eSchristos } 33769689912eSchristos } 33779689912eSchristos 33789689912eSchristos if (result == DNS_R_PARTIALMATCH) { 33799689912eSchristos partial_match: 33809689912eSchristos if (search.zonecut != NULL) { 33819689912eSchristos result = setup_delegation( 33829689912eSchristos &search, nodep, foundname, rdataset, 33839689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 33849689912eSchristos goto tree_exit; 33859689912eSchristos } 33869689912eSchristos 33879689912eSchristos if (search.wild) { 33889689912eSchristos /* 33899689912eSchristos * At least one of the levels in the search chain 33909689912eSchristos * potentially has a wildcard. For each such level, 33919689912eSchristos * we must see if there's a matching wildcard active 33929689912eSchristos * in the current version. 33939689912eSchristos */ 33949689912eSchristos result = find_wildcard(&search, &node, name); 33959689912eSchristos if (result == ISC_R_SUCCESS) { 33969689912eSchristos dns_name_copy(name, foundname); 33979689912eSchristos wild = true; 33989689912eSchristos goto found; 33999689912eSchristos } else if (result != ISC_R_NOTFOUND) { 34009689912eSchristos goto tree_exit; 34019689912eSchristos } 34029689912eSchristos } 34039689912eSchristos 34049689912eSchristos active = false; 34059689912eSchristos if (!nsec3) { 34069689912eSchristos /* 34079689912eSchristos * The NSEC3 tree won't have empty nodes, 34089689912eSchristos * so it isn't necessary to check for them. 34099689912eSchristos */ 34109689912eSchristos dns_qpiter_t iter = search.iter; 34119689912eSchristos active = activeempty(&search, &iter, name); 34129689912eSchristos } 34139689912eSchristos 34149689912eSchristos /* 34159689912eSchristos * If we're here, then the name does not exist, is not 34169689912eSchristos * beneath a zonecut, and there's no matching wildcard. 34179689912eSchristos */ 34189689912eSchristos if ((search.version->secure && !search.version->havensec3) || 34199689912eSchristos nsec3) 34209689912eSchristos { 34219689912eSchristos result = find_closest_nsec( 34229689912eSchristos &search, nodep, foundname, rdataset, 34239689912eSchristos sigrdataset, nsec3, 34249689912eSchristos search.version->secure DNS__DB_FLARG_PASS); 34259689912eSchristos if (result == ISC_R_SUCCESS) { 34269689912eSchristos result = active ? DNS_R_EMPTYNAME 34279689912eSchristos : DNS_R_NXDOMAIN; 34289689912eSchristos } 34299689912eSchristos } else { 34309689912eSchristos result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN; 34319689912eSchristos } 34329689912eSchristos goto tree_exit; 34339689912eSchristos } else if (result != ISC_R_SUCCESS) { 34349689912eSchristos goto tree_exit; 34359689912eSchristos } 34369689912eSchristos 34379689912eSchristos found: 34389689912eSchristos /* 34399689912eSchristos * We have found a node whose name is the desired name, or we 34409689912eSchristos * have matched a wildcard. 34419689912eSchristos */ 34429689912eSchristos 34439689912eSchristos lock = &search.qpdb->node_locks[node->locknum].lock; 34449689912eSchristos NODE_RDLOCK(lock, &nlocktype); 34459689912eSchristos 34469689912eSchristos if (search.zonecut != NULL) { 34479689912eSchristos /* 34489689912eSchristos * If we're beneath a zone cut, we don't want to look for 34499689912eSchristos * CNAMEs because they're not legitimate zone glue. 34509689912eSchristos */ 34519689912eSchristos cname_ok = false; 34529689912eSchristos } else { 34539689912eSchristos /* 34549689912eSchristos * The node may be a zone cut itself. If it might be one, 34559689912eSchristos * make sure we check for it later. 34569689912eSchristos * 34579689912eSchristos * DS records live above the zone cut in ordinary zone so 34589689912eSchristos * we want to ignore any referral. 34599689912eSchristos * 34609689912eSchristos * Stub zones don't have anything "above" the delegation so 34619689912eSchristos * we always return a referral. 34629689912eSchristos */ 34639689912eSchristos if (node->delegating && ((node != search.qpdb->origin && 34649689912eSchristos !dns_rdatatype_atparent(type)) || 34659689912eSchristos IS_STUB(search.qpdb))) 34669689912eSchristos { 34679689912eSchristos maybe_zonecut = true; 34689689912eSchristos } 34699689912eSchristos } 34709689912eSchristos 34719689912eSchristos /* 34729689912eSchristos * Certain DNSSEC types are not subject to CNAME matching 34739689912eSchristos * (RFC4035, section 2.5 and RFC3007). 34749689912eSchristos * 34759689912eSchristos * We don't check for RRSIG, because we don't store RRSIG records 34769689912eSchristos * directly. 34779689912eSchristos */ 34789689912eSchristos if (type == dns_rdatatype_key || type == dns_rdatatype_nsec) { 34799689912eSchristos cname_ok = false; 34809689912eSchristos } 34819689912eSchristos 34829689912eSchristos /* 34839689912eSchristos * We now go looking for rdata... 34849689912eSchristos */ 34859689912eSchristos 34869689912eSchristos sigtype = DNS_SIGTYPE(type); 34879689912eSchristos empty_node = true; 34889689912eSchristos for (header = node->data; header != NULL; header = header_next) { 34899689912eSchristos header_next = header->next; 34909689912eSchristos /* 34919689912eSchristos * Look for an active, extant rdataset. 34929689912eSchristos */ 34939689912eSchristos do { 34949689912eSchristos if (header->serial <= search.serial && !IGNORE(header)) 34959689912eSchristos { 34969689912eSchristos if (NONEXISTENT(header)) { 34979689912eSchristos header = NULL; 34989689912eSchristos } 34999689912eSchristos break; 35009689912eSchristos } else { 35019689912eSchristos header = header->down; 35029689912eSchristos } 35039689912eSchristos } while (header != NULL); 35049689912eSchristos if (header != NULL) { 35059689912eSchristos /* 35069689912eSchristos * We now know that there is at least one active 35079689912eSchristos * rdataset at this node. 35089689912eSchristos */ 35099689912eSchristos empty_node = false; 35109689912eSchristos 35119689912eSchristos /* 35129689912eSchristos * Do special zone cut handling, if requested. 35139689912eSchristos */ 35149689912eSchristos if (maybe_zonecut && header->type == dns_rdatatype_ns) { 35159689912eSchristos /* 35169689912eSchristos * We increment the reference count on node to 35179689912eSchristos * ensure that search->zonecut_header will 35189689912eSchristos * still be valid later. 35199689912eSchristos */ 35209689912eSchristos newref(search.qpdb, node DNS__DB_FLARG_PASS); 35219689912eSchristos search.zonecut = node; 35229689912eSchristos search.zonecut_header = header; 35239689912eSchristos search.zonecut_sigheader = NULL; 35249689912eSchristos search.need_cleanup = true; 35259689912eSchristos maybe_zonecut = false; 35269689912eSchristos at_zonecut = true; 35279689912eSchristos /* 35289689912eSchristos * It is not clear if KEY should still be 35299689912eSchristos * allowed at the parent side of the zone 35309689912eSchristos * cut or not. It is needed for RFC3007 35319689912eSchristos * validated updates. 35329689912eSchristos */ 35339689912eSchristos if ((search.options & DNS_DBFIND_GLUEOK) == 0 && 35349689912eSchristos type != dns_rdatatype_nsec && 35359689912eSchristos type != dns_rdatatype_key) 35369689912eSchristos { 35379689912eSchristos /* 35389689912eSchristos * Glue is not OK, but any answer we 35399689912eSchristos * could return would be glue. Return 35409689912eSchristos * the delegation. 35419689912eSchristos */ 35429689912eSchristos found = NULL; 35439689912eSchristos break; 35449689912eSchristos } 35459689912eSchristos if (found != NULL && foundsig != NULL) { 35469689912eSchristos break; 35479689912eSchristos } 35489689912eSchristos } 35499689912eSchristos 35509689912eSchristos /* 35519689912eSchristos * If the NSEC3 record doesn't match the chain 35529689912eSchristos * we are using behave as if it isn't here. 35539689912eSchristos */ 35549689912eSchristos if (header->type == dns_rdatatype_nsec3 && 35559689912eSchristos !matchparams(header, &search)) 35569689912eSchristos { 35579689912eSchristos NODE_UNLOCK(lock, &nlocktype); 35589689912eSchristos goto partial_match; 35599689912eSchristos } 35609689912eSchristos /* 35619689912eSchristos * If we found a type we were looking for, 35629689912eSchristos * remember it. 35639689912eSchristos */ 35649689912eSchristos if (header->type == type || type == dns_rdatatype_any || 35659689912eSchristos (header->type == dns_rdatatype_cname && cname_ok)) 35669689912eSchristos { 35679689912eSchristos /* 35689689912eSchristos * We've found the answer! 35699689912eSchristos */ 35709689912eSchristos found = header; 35719689912eSchristos if (header->type == dns_rdatatype_cname && 35729689912eSchristos cname_ok) 35739689912eSchristos { 35749689912eSchristos /* 35759689912eSchristos * We may be finding a CNAME instead 35769689912eSchristos * of the desired type. 35779689912eSchristos * 35789689912eSchristos * If we've already got the CNAME RRSIG, 35799689912eSchristos * use it, otherwise change sigtype 35809689912eSchristos * so that we find it. 35819689912eSchristos */ 35829689912eSchristos if (cnamesig != NULL) { 35839689912eSchristos foundsig = cnamesig; 35849689912eSchristos } else { 35859689912eSchristos sigtype = DNS_SIGTYPE( 35869689912eSchristos dns_rdatatype_cname); 35879689912eSchristos } 35889689912eSchristos } 35899689912eSchristos /* 35909689912eSchristos * If we've got all we need, end the search. 35919689912eSchristos */ 35929689912eSchristos if (!maybe_zonecut && foundsig != NULL) { 35939689912eSchristos break; 35949689912eSchristos } 35959689912eSchristos } else if (header->type == sigtype) { 35969689912eSchristos /* 35979689912eSchristos * We've found the RRSIG rdataset for our 35989689912eSchristos * target type. Remember it. 35999689912eSchristos */ 36009689912eSchristos foundsig = header; 36019689912eSchristos /* 36029689912eSchristos * If we've got all we need, end the search. 36039689912eSchristos */ 36049689912eSchristos if (!maybe_zonecut && found != NULL) { 36059689912eSchristos break; 36069689912eSchristos } 36079689912eSchristos } else if (header->type == dns_rdatatype_nsec && 36089689912eSchristos !search.version->havensec3) 36099689912eSchristos { 36109689912eSchristos /* 36119689912eSchristos * Remember a NSEC rdataset even if we're 36129689912eSchristos * not specifically looking for it, because 36139689912eSchristos * we might need it later. 36149689912eSchristos */ 36159689912eSchristos nsecheader = header; 36169689912eSchristos } else if (header->type == 36179689912eSchristos DNS_SIGTYPE(dns_rdatatype_nsec) && 36189689912eSchristos !search.version->havensec3) 36199689912eSchristos { 36209689912eSchristos /* 36219689912eSchristos * If we need the NSEC rdataset, we'll also 36229689912eSchristos * need its signature. 36239689912eSchristos */ 36249689912eSchristos nsecsig = header; 36259689912eSchristos } else if (cname_ok && 36269689912eSchristos header->type == 36279689912eSchristos DNS_SIGTYPE(dns_rdatatype_cname)) 36289689912eSchristos { 36299689912eSchristos /* 36309689912eSchristos * If we get a CNAME match, we'll also need 36319689912eSchristos * its signature. 36329689912eSchristos */ 36339689912eSchristos cnamesig = header; 36349689912eSchristos } 36359689912eSchristos } 36369689912eSchristos } 36379689912eSchristos 36389689912eSchristos if (empty_node) { 36399689912eSchristos /* 36409689912eSchristos * We have an exact match for the name, but there are no 36419689912eSchristos * active rdatasets in the desired version. That means that 36429689912eSchristos * this node doesn't exist in the desired version, and that 36439689912eSchristos * we really have a partial match. 36449689912eSchristos */ 36459689912eSchristos if (!wild) { 36469689912eSchristos NODE_UNLOCK(lock, &nlocktype); 36479689912eSchristos goto partial_match; 36489689912eSchristos } 36499689912eSchristos } 36509689912eSchristos 36519689912eSchristos /* 36529689912eSchristos * If we didn't find what we were looking for... 36539689912eSchristos */ 36549689912eSchristos if (found == NULL) { 36559689912eSchristos if (search.zonecut != NULL) { 36569689912eSchristos /* 36579689912eSchristos * We were trying to find glue at a node beneath a 36589689912eSchristos * zone cut, but didn't. 36599689912eSchristos * 36609689912eSchristos * Return the delegation. 36619689912eSchristos */ 36629689912eSchristos NODE_UNLOCK(lock, &nlocktype); 36639689912eSchristos result = setup_delegation( 36649689912eSchristos &search, nodep, foundname, rdataset, 36659689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 36669689912eSchristos goto tree_exit; 36679689912eSchristos } 36689689912eSchristos /* 36699689912eSchristos * The desired type doesn't exist. 36709689912eSchristos */ 36719689912eSchristos result = DNS_R_NXRRSET; 36729689912eSchristos if (search.version->secure && !search.version->havensec3 && 36739689912eSchristos (nsecheader == NULL || nsecsig == NULL)) 36749689912eSchristos { 36759689912eSchristos /* 36769689912eSchristos * The zone is secure but there's no NSEC, 36779689912eSchristos * or the NSEC has no signature! 36789689912eSchristos */ 36799689912eSchristos if (!wild) { 36809689912eSchristos result = DNS_R_BADDB; 36819689912eSchristos goto node_exit; 36829689912eSchristos } 36839689912eSchristos 36849689912eSchristos NODE_UNLOCK(lock, &nlocktype); 36859689912eSchristos result = find_closest_nsec( 36869689912eSchristos &search, nodep, foundname, rdataset, 36879689912eSchristos sigrdataset, false, 36889689912eSchristos search.version->secure DNS__DB_FLARG_PASS); 36899689912eSchristos if (result == ISC_R_SUCCESS) { 36909689912eSchristos result = DNS_R_EMPTYWILD; 36919689912eSchristos } 36929689912eSchristos goto tree_exit; 36939689912eSchristos } 36949689912eSchristos if (nodep != NULL) { 36959689912eSchristos newref(search.qpdb, node DNS__DB_FLARG_PASS); 36969689912eSchristos *nodep = node; 36979689912eSchristos } 36989689912eSchristos if (search.version->secure && !search.version->havensec3) { 36999689912eSchristos bindrdataset(search.qpdb, node, nsecheader, 0, 37009689912eSchristos rdataset DNS__DB_FLARG_PASS); 37019689912eSchristos if (nsecsig != NULL) { 37029689912eSchristos bindrdataset(search.qpdb, node, nsecsig, 0, 37039689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 37049689912eSchristos } 37059689912eSchristos } 37069689912eSchristos if (wild) { 37079689912eSchristos foundname->attributes.wildcard = true; 37089689912eSchristos } 37099689912eSchristos goto node_exit; 37109689912eSchristos } 37119689912eSchristos 37129689912eSchristos /* 37139689912eSchristos * We found what we were looking for, or we found a CNAME. 37149689912eSchristos */ 37159689912eSchristos if (type != found->type && type != dns_rdatatype_any && 37169689912eSchristos found->type == dns_rdatatype_cname) 37179689912eSchristos { 37189689912eSchristos /* 37199689912eSchristos * We weren't doing an ANY query and we found a CNAME instead 37209689912eSchristos * of the type we were looking for, so we need to indicate 37219689912eSchristos * that result to the caller. 37229689912eSchristos */ 37239689912eSchristos result = DNS_R_CNAME; 37249689912eSchristos } else if (search.zonecut != NULL) { 37259689912eSchristos /* 37269689912eSchristos * If we're beneath a zone cut, we must indicate that the 37279689912eSchristos * result is glue, unless we're actually at the zone cut 37289689912eSchristos * and the type is NSEC or KEY. 37299689912eSchristos */ 37309689912eSchristos if (search.zonecut == node) { 37319689912eSchristos /* 37329689912eSchristos * It is not clear if KEY should still be 37339689912eSchristos * allowed at the parent side of the zone 37349689912eSchristos * cut or not. It is needed for RFC3007 37359689912eSchristos * validated updates. 37369689912eSchristos */ 37379689912eSchristos if (type == dns_rdatatype_nsec || 37389689912eSchristos type == dns_rdatatype_nsec3 || 37399689912eSchristos type == dns_rdatatype_key) 37409689912eSchristos { 37419689912eSchristos result = ISC_R_SUCCESS; 37429689912eSchristos } else if (type == dns_rdatatype_any) { 37439689912eSchristos result = DNS_R_ZONECUT; 37449689912eSchristos } else { 37459689912eSchristos result = DNS_R_GLUE; 37469689912eSchristos } 37479689912eSchristos } else { 37489689912eSchristos result = DNS_R_GLUE; 37499689912eSchristos } 37509689912eSchristos } else { 37519689912eSchristos /* 37529689912eSchristos * An ordinary successful query! 37539689912eSchristos */ 37549689912eSchristos result = ISC_R_SUCCESS; 37559689912eSchristos } 37569689912eSchristos 37579689912eSchristos if (nodep != NULL) { 37589689912eSchristos if (!at_zonecut) { 37599689912eSchristos newref(search.qpdb, node DNS__DB_FLARG_PASS); 37609689912eSchristos } else { 37619689912eSchristos search.need_cleanup = false; 37629689912eSchristos } 37639689912eSchristos *nodep = node; 37649689912eSchristos } 37659689912eSchristos 37669689912eSchristos if (type != dns_rdatatype_any) { 37679689912eSchristos bindrdataset(search.qpdb, node, found, 0, 37689689912eSchristos rdataset DNS__DB_FLARG_PASS); 37699689912eSchristos if (foundsig != NULL) { 37709689912eSchristos bindrdataset(search.qpdb, node, foundsig, 0, 37719689912eSchristos sigrdataset DNS__DB_FLARG_PASS); 37729689912eSchristos } 37739689912eSchristos } 37749689912eSchristos 37759689912eSchristos if (wild) { 37769689912eSchristos foundname->attributes.wildcard = true; 37779689912eSchristos } 37789689912eSchristos 37799689912eSchristos node_exit: 37809689912eSchristos NODE_UNLOCK(lock, &nlocktype); 37819689912eSchristos 37829689912eSchristos tree_exit: 37839689912eSchristos if (nsec3) { 37849689912eSchristos dns_qpread_destroy(qpdb->nsec3, &search.qpr); 37859689912eSchristos } else { 37869689912eSchristos dns_qpread_destroy(qpdb->tree, &search.qpr); 37879689912eSchristos } 37889689912eSchristos 37899689912eSchristos /* 37909689912eSchristos * If we found a zonecut but aren't going to use it, we have to 37919689912eSchristos * let go of it. 37929689912eSchristos */ 37939689912eSchristos if (search.need_cleanup) { 37949689912eSchristos node = search.zonecut; 37959689912eSchristos INSIST(node != NULL); 37969689912eSchristos lock = &(search.qpdb->node_locks[node->locknum].lock); 37979689912eSchristos 37989689912eSchristos NODE_RDLOCK(lock, &nlocktype); 37999689912eSchristos decref(search.qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS); 38009689912eSchristos NODE_UNLOCK(lock, &nlocktype); 38019689912eSchristos } 38029689912eSchristos 38039689912eSchristos if (close_version) { 38049689912eSchristos closeversion(db, &version, false DNS__DB_FLARG_PASS); 38059689912eSchristos } 38069689912eSchristos 38079689912eSchristos return result; 38089689912eSchristos } 38099689912eSchristos 38109689912eSchristos static isc_result_t 38119689912eSchristos allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, 38129689912eSchristos unsigned int options, isc_stdtime_t now ISC_ATTR_UNUSED, 38139689912eSchristos dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 38149689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 38159689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 38169689912eSchristos qpz_version_t *version = dbversion; 38179689912eSchristos qpdb_rdatasetiter_t *iterator = NULL; 38189689912eSchristos 38199689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 38209689912eSchristos 38219689912eSchristos if (version == NULL) { 38229689912eSchristos currentversion(db, (dns_dbversion_t **)(void *)(&version)); 38239689912eSchristos } else { 38249689912eSchristos INSIST(version->qpdb == qpdb); 38259689912eSchristos isc_refcount_increment(&version->references); 38269689912eSchristos } 38279689912eSchristos 38289689912eSchristos iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator)); 38299689912eSchristos *iterator = (qpdb_rdatasetiter_t){ 38309689912eSchristos .common.methods = &rdatasetiter_methods, 38319689912eSchristos .common.db = db, 38329689912eSchristos .common.node = node, 38339689912eSchristos .common.version = (dns_dbversion_t *)version, 38349689912eSchristos .common.options = options, 38359689912eSchristos .common.magic = DNS_RDATASETITER_MAGIC, 38369689912eSchristos }; 38379689912eSchristos 38389689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 38399689912eSchristos 38409689912eSchristos *iteratorp = (dns_rdatasetiter_t *)iterator; 38419689912eSchristos return ISC_R_SUCCESS; 38429689912eSchristos } 38439689912eSchristos 38449689912eSchristos static void 38459689912eSchristos attachnode(dns_db_t *db, dns_dbnode_t *source, 38469689912eSchristos dns_dbnode_t **targetp DNS__DB_FLARG) { 38479689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 38489689912eSchristos qpznode_t *node = (qpznode_t *)source; 38499689912eSchristos 38509689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 38519689912eSchristos REQUIRE(targetp != NULL && *targetp == NULL); 38529689912eSchristos 38539689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 38549689912eSchristos 38559689912eSchristos *targetp = source; 38569689912eSchristos } 38579689912eSchristos 38589689912eSchristos static void 38599689912eSchristos detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) { 38609689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 38619689912eSchristos qpznode_t *node = NULL; 38629689912eSchristos bool want_free = false; 38639689912eSchristos bool inactive = false; 38649689912eSchristos db_nodelock_t *nodelock = NULL; 38659689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 38669689912eSchristos 38679689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 38689689912eSchristos REQUIRE(targetp != NULL && *targetp != NULL); 38699689912eSchristos 38709689912eSchristos node = (qpznode_t *)(*targetp); 38719689912eSchristos nodelock = &qpdb->node_locks[node->locknum]; 38729689912eSchristos 38739689912eSchristos NODE_RDLOCK(&nodelock->lock, &nlocktype); 38749689912eSchristos decref(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS); 38759689912eSchristos if (isc_refcount_current(&nodelock->references) == 0 && 38769689912eSchristos nodelock->exiting) 38779689912eSchristos { 38789689912eSchristos inactive = true; 38799689912eSchristos } 38809689912eSchristos NODE_UNLOCK(&nodelock->lock, &nlocktype); 38819689912eSchristos 38829689912eSchristos *targetp = NULL; 38839689912eSchristos 38849689912eSchristos if (inactive) { 38859689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 38869689912eSchristos qpdb->active--; 38879689912eSchristos if (qpdb->active == 0) { 38889689912eSchristos want_free = true; 38899689912eSchristos } 38909689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 38919689912eSchristos if (want_free) { 38929689912eSchristos char buf[DNS_NAME_FORMATSIZE]; 38939689912eSchristos if (dns_name_dynamic(&qpdb->common.origin)) { 38949689912eSchristos dns_name_format(&qpdb->common.origin, buf, 38959689912eSchristos sizeof(buf)); 38969689912eSchristos } else { 38979689912eSchristos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 38989689912eSchristos } 38999689912eSchristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 39009689912eSchristos DNS_LOGMODULE_DB, ISC_LOG_DEBUG(1), 39019689912eSchristos "calling free_qpdb(%s)", buf); 39029689912eSchristos free_qpdb(qpdb, true); 39039689912eSchristos } 39049689912eSchristos } 39059689912eSchristos } 39069689912eSchristos 39079689912eSchristos static unsigned int 39089689912eSchristos nodecount(dns_db_t *db, dns_dbtree_t tree) { 39099689912eSchristos qpzonedb_t *qpdb = NULL; 39109689912eSchristos dns_qp_memusage_t mu; 39119689912eSchristos 39129689912eSchristos qpdb = (qpzonedb_t *)db; 39139689912eSchristos 39149689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 39159689912eSchristos 39169689912eSchristos switch (tree) { 39179689912eSchristos case dns_dbtree_main: 39189689912eSchristos mu = dns_qpmulti_memusage(qpdb->tree); 39199689912eSchristos break; 39209689912eSchristos case dns_dbtree_nsec: 39219689912eSchristos mu = dns_qpmulti_memusage(qpdb->nsec); 39229689912eSchristos break; 39239689912eSchristos case dns_dbtree_nsec3: 39249689912eSchristos mu = dns_qpmulti_memusage(qpdb->nsec3); 39259689912eSchristos break; 39269689912eSchristos default: 39279689912eSchristos UNREACHABLE(); 39289689912eSchristos } 39299689912eSchristos 39309689912eSchristos return mu.leaves; 39319689912eSchristos } 39329689912eSchristos 39339689912eSchristos static void 39349689912eSchristos setloop(dns_db_t *db, isc_loop_t *loop) { 39359689912eSchristos qpzonedb_t *qpdb = NULL; 39369689912eSchristos 39379689912eSchristos qpdb = (qpzonedb_t *)db; 39389689912eSchristos 39399689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 39409689912eSchristos 39419689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 39429689912eSchristos if (qpdb->loop != NULL) { 39439689912eSchristos isc_loop_detach(&qpdb->loop); 39449689912eSchristos } 39459689912eSchristos if (loop != NULL) { 39469689912eSchristos isc_loop_attach(loop, &qpdb->loop); 39479689912eSchristos } 39489689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 39499689912eSchristos } 39509689912eSchristos 39519689912eSchristos static isc_result_t 39529689912eSchristos getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 39539689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 39549689912eSchristos qpznode_t *onode = NULL; 39559689912eSchristos 39569689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 39579689912eSchristos REQUIRE(nodep != NULL && *nodep == NULL); 39589689912eSchristos 39599689912eSchristos /* Note that the access to the origin node doesn't require a DB lock */ 39609689912eSchristos onode = (qpznode_t *)qpdb->origin; 39619689912eSchristos INSIST(onode != NULL); 39629689912eSchristos newref(qpdb, onode DNS__DB_FLARG_PASS); 39639689912eSchristos *nodep = onode; 39649689912eSchristos 39659689912eSchristos return ISC_R_SUCCESS; 39669689912eSchristos } 39679689912eSchristos 39689689912eSchristos static void 39699689912eSchristos locknode(dns_db_t *db, dns_dbnode_t *dbnode, isc_rwlocktype_t type) { 39709689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 39719689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 39729689912eSchristos 39739689912eSchristos RWLOCK(&qpdb->node_locks[node->locknum].lock, type); 39749689912eSchristos } 39759689912eSchristos 39769689912eSchristos static void 39779689912eSchristos unlocknode(dns_db_t *db, dns_dbnode_t *dbnode, isc_rwlocktype_t type) { 39789689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 39799689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 39809689912eSchristos 39819689912eSchristos RWUNLOCK(&qpdb->node_locks[node->locknum].lock, type); 39829689912eSchristos } 39839689912eSchristos 39849689912eSchristos static void 39859689912eSchristos deletedata(dns_db_t *db ISC_ATTR_UNUSED, dns_dbnode_t *node ISC_ATTR_UNUSED, 39869689912eSchristos void *data) { 39879689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 39889689912eSchristos dns_slabheader_t *header = data; 39899689912eSchristos 39909689912eSchristos if (header->heap != NULL && header->heap_index != 0) { 39919689912eSchristos RWLOCK(&qpdb->lock, isc_rwlocktype_write); 39929689912eSchristos isc_heap_delete(header->heap, header->heap_index); 39939689912eSchristos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); 39949689912eSchristos } 39959689912eSchristos header->heap_index = 0; 39969689912eSchristos } 39979689912eSchristos 39989689912eSchristos /* 39999689912eSchristos * Rdataset Iterator Methods 40009689912eSchristos */ 40019689912eSchristos 40029689912eSchristos static void 40039689912eSchristos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 40049689912eSchristos qpdb_rdatasetiter_t *qrditer = NULL; 40059689912eSchristos 40069689912eSchristos qrditer = (qpdb_rdatasetiter_t *)(*iteratorp); 40079689912eSchristos 40089689912eSchristos if (qrditer->common.version != NULL) { 40099689912eSchristos closeversion(qrditer->common.db, &qrditer->common.version, 40109689912eSchristos false DNS__DB_FLARG_PASS); 40119689912eSchristos } 40129689912eSchristos dns__db_detachnode(qrditer->common.db, 40139689912eSchristos &qrditer->common.node DNS__DB_FLARG_PASS); 40149689912eSchristos isc_mem_put(qrditer->common.db->mctx, qrditer, sizeof(*qrditer)); 40159689912eSchristos 40169689912eSchristos *iteratorp = NULL; 40179689912eSchristos } 40189689912eSchristos 40199689912eSchristos static isc_result_t 40209689912eSchristos rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 40219689912eSchristos qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; 40229689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db); 40239689912eSchristos qpznode_t *node = qrditer->common.node; 40249689912eSchristos qpz_version_t *version = qrditer->common.version; 40259689912eSchristos dns_slabheader_t *header = NULL, *top_next = NULL; 40269689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 40279689912eSchristos 40289689912eSchristos NODE_RDLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 40299689912eSchristos 40309689912eSchristos for (header = node->data; header != NULL; header = top_next) { 40319689912eSchristos top_next = header->next; 40329689912eSchristos do { 40339689912eSchristos if (header->serial <= version->serial && 40349689912eSchristos !IGNORE(header)) 40359689912eSchristos { 40369689912eSchristos if (NONEXISTENT(header)) { 40379689912eSchristos header = NULL; 40389689912eSchristos } 40399689912eSchristos break; 40409689912eSchristos } else { 40419689912eSchristos header = header->down; 40429689912eSchristos } 40439689912eSchristos } while (header != NULL); 40449689912eSchristos if (header != NULL) { 40459689912eSchristos break; 40469689912eSchristos } 40479689912eSchristos } 40489689912eSchristos 40499689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 40509689912eSchristos 40519689912eSchristos qrditer->current = header; 40529689912eSchristos 40539689912eSchristos if (header == NULL) { 40549689912eSchristos return ISC_R_NOMORE; 40559689912eSchristos } 40569689912eSchristos 40579689912eSchristos return ISC_R_SUCCESS; 40589689912eSchristos } 40599689912eSchristos 40609689912eSchristos static isc_result_t 40619689912eSchristos rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 40629689912eSchristos qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; 40639689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db); 40649689912eSchristos qpznode_t *node = qrditer->common.node; 40659689912eSchristos qpz_version_t *version = qrditer->common.version; 40669689912eSchristos dns_slabheader_t *header = NULL, *top_next = NULL; 40679689912eSchristos dns_typepair_t type, negtype; 40689689912eSchristos dns_rdatatype_t rdtype; 40699689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 40709689912eSchristos 40719689912eSchristos header = qrditer->current; 40729689912eSchristos if (header == NULL) { 40739689912eSchristos return ISC_R_NOMORE; 40749689912eSchristos } 40759689912eSchristos 40769689912eSchristos NODE_RDLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 40779689912eSchristos 40789689912eSchristos type = header->type; 40799689912eSchristos rdtype = DNS_TYPEPAIR_TYPE(header->type); 40809689912eSchristos negtype = DNS_TYPEPAIR_VALUE(0, rdtype); 40819689912eSchristos 40829689912eSchristos /* 40839689912eSchristos * Find the start of the header chain for the next type 40849689912eSchristos * by walking back up the list. 40859689912eSchristos */ 40869689912eSchristos top_next = header->next; 40879689912eSchristos while (top_next != NULL && 40889689912eSchristos (top_next->type == type || top_next->type == negtype)) 40899689912eSchristos { 40909689912eSchristos top_next = top_next->next; 40919689912eSchristos } 40929689912eSchristos for (header = top_next; header != NULL; header = top_next) { 40939689912eSchristos top_next = header->next; 40949689912eSchristos do { 40959689912eSchristos if (header->serial <= version->serial && 40969689912eSchristos !IGNORE(header)) 40979689912eSchristos { 40989689912eSchristos if (NONEXISTENT(header)) { 40999689912eSchristos header = NULL; 41009689912eSchristos } 41019689912eSchristos break; 41029689912eSchristos } else { 41039689912eSchristos header = header->down; 41049689912eSchristos } 41059689912eSchristos } while (header != NULL); 41069689912eSchristos if (header != NULL) { 41079689912eSchristos break; 41089689912eSchristos } 41099689912eSchristos /* 41109689912eSchristos * Find the start of the header chain for the next type 41119689912eSchristos * by walking back up the list. 41129689912eSchristos */ 41139689912eSchristos while (top_next != NULL && 41149689912eSchristos (top_next->type == type || top_next->type == negtype)) 41159689912eSchristos { 41169689912eSchristos top_next = top_next->next; 41179689912eSchristos } 41189689912eSchristos } 41199689912eSchristos 41209689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 41219689912eSchristos 41229689912eSchristos qrditer->current = header; 41239689912eSchristos 41249689912eSchristos if (header == NULL) { 41259689912eSchristos return ISC_R_NOMORE; 41269689912eSchristos } 41279689912eSchristos 41289689912eSchristos return ISC_R_SUCCESS; 41299689912eSchristos } 41309689912eSchristos 41319689912eSchristos static void 41329689912eSchristos rdatasetiter_current(dns_rdatasetiter_t *iterator, 41339689912eSchristos dns_rdataset_t *rdataset DNS__DB_FLARG) { 41349689912eSchristos qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; 41359689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db); 41369689912eSchristos qpznode_t *node = qrditer->common.node; 41379689912eSchristos dns_slabheader_t *header = NULL; 41389689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 41399689912eSchristos 41409689912eSchristos header = qrditer->current; 41419689912eSchristos REQUIRE(header != NULL); 41429689912eSchristos 41439689912eSchristos NODE_RDLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 41449689912eSchristos 41459689912eSchristos bindrdataset(qpdb, node, header, qrditer->common.now, 41469689912eSchristos rdataset DNS__DB_FLARG_PASS); 41479689912eSchristos 41489689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 41499689912eSchristos } 41509689912eSchristos 41519689912eSchristos /* 41529689912eSchristos * Database Iterator Methods 41539689912eSchristos */ 41549689912eSchristos static void 41559689912eSchristos reference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) { 41569689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iter->common.db; 41579689912eSchristos qpznode_t *node = iter->node; 41589689912eSchristos 41599689912eSchristos if (node == NULL) { 41609689912eSchristos return; 41619689912eSchristos } 41629689912eSchristos 41639689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 41649689912eSchristos } 41659689912eSchristos 41669689912eSchristos static void 41679689912eSchristos dereference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) { 41689689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iter->common.db; 41699689912eSchristos qpznode_t *node = iter->node; 41709689912eSchristos isc_rwlock_t *lock = NULL; 41719689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 41729689912eSchristos 41739689912eSchristos if (node == NULL) { 41749689912eSchristos return; 41759689912eSchristos } 41769689912eSchristos 41779689912eSchristos lock = &qpdb->node_locks[node->locknum].lock; 41789689912eSchristos NODE_RDLOCK(lock, &nlocktype); 41799689912eSchristos decref(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS); 41809689912eSchristos NODE_UNLOCK(lock, &nlocktype); 41819689912eSchristos iter->node = NULL; 41829689912eSchristos } 41839689912eSchristos 41849689912eSchristos static void 41859689912eSchristos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) { 41869689912eSchristos qpdb_dbiterator_t *iter = (qpdb_dbiterator_t *)(*iteratorp); 41879689912eSchristos dns_db_t *db = NULL; 41889689912eSchristos 41899689912eSchristos dereference_iter_node(iter DNS__DB_FLARG_PASS); 41909689912eSchristos 41919689912eSchristos dns_db_attach(iter->common.db, &db); 41929689912eSchristos dns_db_detach(&iter->common.db); 41939689912eSchristos 41949689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 41959689912eSchristos dns_qpsnap_destroy(qpdb->tree, &iter->tsnap); 41969689912eSchristos dns_qpsnap_destroy(qpdb->nsec3, &iter->nsnap); 41979689912eSchristos 41989689912eSchristos isc_mem_put(db->mctx, iter, sizeof(*iter)); 41999689912eSchristos dns_db_detach(&db); 42009689912eSchristos 42019689912eSchristos *iteratorp = NULL; 42029689912eSchristos } 42039689912eSchristos 42049689912eSchristos static isc_result_t 42059689912eSchristos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) { 42069689912eSchristos isc_result_t result; 42079689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 42089689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db; 42099689912eSchristos 42109689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS && 42119689912eSchristos qpdbiter->result != ISC_R_NOTFOUND && 42129689912eSchristos qpdbiter->result != DNS_R_PARTIALMATCH && 42139689912eSchristos qpdbiter->result != ISC_R_NOMORE) 42149689912eSchristos { 42159689912eSchristos return qpdbiter->result; 42169689912eSchristos } 42179689912eSchristos 42189689912eSchristos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 42199689912eSchristos 42209689912eSchristos switch (qpdbiter->nsec3mode) { 42219689912eSchristos case nsec3only: 42229689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 42239689912eSchristos dns_qpiter_init(qpdbiter->nsnap, qpdbiter->current); 42249689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 42259689912eSchristos (void **)&qpdbiter->node, NULL); 42269689912eSchristos if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { 42279689912eSchristos /* If we're in the NSEC3 tree, skip the origin */ 42289689912eSchristos if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) { 42299689912eSchristos result = dns_qpiter_next( 42309689912eSchristos qpdbiter->current, NULL, 42319689912eSchristos (void **)&qpdbiter->node, NULL); 42329689912eSchristos } 42339689912eSchristos } 42349689912eSchristos break; 42359689912eSchristos case nonsec3: 42369689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 42379689912eSchristos dns_qpiter_init(qpdbiter->tsnap, qpdbiter->current); 42389689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 42399689912eSchristos (void **)&qpdbiter->node, NULL); 42409689912eSchristos break; 42419689912eSchristos case full: 42429689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 42439689912eSchristos dns_qpiter_init(qpdbiter->tsnap, qpdbiter->current); 42449689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 42459689912eSchristos (void **)&qpdbiter->node, NULL); 42469689912eSchristos if (result == ISC_R_NOMORE) { 42479689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 42489689912eSchristos dns_qpiter_init(qpdbiter->nsnap, qpdbiter->current); 42499689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 42509689912eSchristos (void **)&qpdbiter->node, 42519689912eSchristos NULL); 42529689912eSchristos } 42539689912eSchristos break; 42549689912eSchristos default: 42559689912eSchristos UNREACHABLE(); 42569689912eSchristos } 42579689912eSchristos 42589689912eSchristos if (result == ISC_R_SUCCESS) { 42599689912eSchristos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 42609689912eSchristos } else { 42619689912eSchristos qpdbiter->node = NULL; 42629689912eSchristos } 42639689912eSchristos qpdbiter->result = result; 42649689912eSchristos return result; 42659689912eSchristos } 42669689912eSchristos 42679689912eSchristos static isc_result_t 42689689912eSchristos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG) { 42699689912eSchristos isc_result_t result; 42709689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 42719689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db; 42729689912eSchristos 42739689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS && 42749689912eSchristos qpdbiter->result != ISC_R_NOTFOUND && 42759689912eSchristos qpdbiter->result != DNS_R_PARTIALMATCH && 42769689912eSchristos qpdbiter->result != ISC_R_NOMORE) 42779689912eSchristos { 42789689912eSchristos return qpdbiter->result; 42799689912eSchristos } 42809689912eSchristos 42819689912eSchristos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 42829689912eSchristos 42839689912eSchristos switch (qpdbiter->nsec3mode) { 42849689912eSchristos case nsec3only: 42859689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 42869689912eSchristos dns_qpiter_init(qpdbiter->nsnap, qpdbiter->current); 42879689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 42889689912eSchristos (void **)&qpdbiter->node, NULL); 42899689912eSchristos if ((result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) && 42909689912eSchristos QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) 42919689912eSchristos { 42929689912eSchristos /* 42939689912eSchristos * NSEC3 tree only has an origin node. 42949689912eSchristos */ 42959689912eSchristos qpdbiter->node = NULL; 42969689912eSchristos result = ISC_R_NOMORE; 42979689912eSchristos } 42989689912eSchristos break; 42999689912eSchristos case nonsec3: 43009689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 43019689912eSchristos dns_qpiter_init(qpdbiter->tsnap, qpdbiter->current); 43029689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 43039689912eSchristos (void **)&qpdbiter->node, NULL); 43049689912eSchristos break; 43059689912eSchristos case full: 43069689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 43079689912eSchristos dns_qpiter_init(qpdbiter->nsnap, qpdbiter->current); 43089689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 43099689912eSchristos (void **)&qpdbiter->node, NULL); 43109689912eSchristos if ((result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) && 43119689912eSchristos QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) 43129689912eSchristos { 43139689912eSchristos /* 43149689912eSchristos * NSEC3 tree only has an origin node. 43159689912eSchristos */ 43169689912eSchristos qpdbiter->node = NULL; 43179689912eSchristos result = ISC_R_NOMORE; 43189689912eSchristos } 43199689912eSchristos if (result == ISC_R_NOMORE) { 43209689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 43219689912eSchristos dns_qpiter_init(qpdbiter->tsnap, qpdbiter->current); 43229689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 43239689912eSchristos (void **)&qpdbiter->node, 43249689912eSchristos NULL); 43259689912eSchristos } 43269689912eSchristos break; 43279689912eSchristos default: 43289689912eSchristos UNREACHABLE(); 43299689912eSchristos } 43309689912eSchristos 43319689912eSchristos if (result == ISC_R_SUCCESS) { 43329689912eSchristos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 43339689912eSchristos } else { 43349689912eSchristos qpdbiter->node = NULL; 43359689912eSchristos } 43369689912eSchristos qpdbiter->result = result; 43379689912eSchristos return result; 43389689912eSchristos } 43399689912eSchristos 43409689912eSchristos static isc_result_t 43419689912eSchristos dbiterator_seek(dns_dbiterator_t *iterator, 43429689912eSchristos const dns_name_t *name DNS__DB_FLARG) { 43439689912eSchristos isc_result_t result, tresult; 43449689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 43459689912eSchristos 43469689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS && 43479689912eSchristos qpdbiter->result != ISC_R_NOTFOUND && 43489689912eSchristos qpdbiter->result != DNS_R_PARTIALMATCH && 43499689912eSchristos qpdbiter->result != ISC_R_NOMORE) 43509689912eSchristos { 43519689912eSchristos return qpdbiter->result; 43529689912eSchristos } 43539689912eSchristos 43549689912eSchristos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 43559689912eSchristos 43569689912eSchristos switch (qpdbiter->nsec3mode) { 43579689912eSchristos case nsec3only: 43589689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 43599689912eSchristos result = dns_qp_lookup(qpdbiter->nsnap, name, NULL, 43609689912eSchristos qpdbiter->current, NULL, 43619689912eSchristos (void **)&qpdbiter->node, NULL); 43629689912eSchristos break; 43639689912eSchristos case nonsec3: 43649689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 43659689912eSchristos result = dns_qp_lookup(qpdbiter->tsnap, name, NULL, 43669689912eSchristos qpdbiter->current, NULL, 43679689912eSchristos (void **)&qpdbiter->node, NULL); 43689689912eSchristos break; 43699689912eSchristos case full: 43709689912eSchristos /* 43719689912eSchristos * Stay on main chain if not found on 43729689912eSchristos * either iterator. 43739689912eSchristos */ 43749689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 43759689912eSchristos result = dns_qp_lookup(qpdbiter->tsnap, name, NULL, 43769689912eSchristos qpdbiter->current, NULL, 43779689912eSchristos (void **)&qpdbiter->node, NULL); 43789689912eSchristos if (result == DNS_R_PARTIALMATCH) { 43799689912eSchristos tresult = dns_qp_lookup(qpdbiter->nsnap, name, NULL, 43809689912eSchristos &qpdbiter->nsec3iter, NULL, 43819689912eSchristos NULL, NULL); 43829689912eSchristos if (tresult == ISC_R_SUCCESS) { 43839689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 43849689912eSchristos result = tresult; 43859689912eSchristos } 43869689912eSchristos } 43879689912eSchristos break; 43889689912eSchristos default: 43899689912eSchristos UNREACHABLE(); 43909689912eSchristos } 43919689912eSchristos 43929689912eSchristos if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { 43939689912eSchristos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 43949689912eSchristos } else { 43959689912eSchristos qpdbiter->node = NULL; 43969689912eSchristos } 43979689912eSchristos 43989689912eSchristos qpdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS 43999689912eSchristos : result; 44009689912eSchristos return result; 44019689912eSchristos } 44029689912eSchristos 44039689912eSchristos static isc_result_t 44049689912eSchristos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) { 44059689912eSchristos isc_result_t result; 44069689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 44079689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db; 44089689912eSchristos 44099689912eSchristos REQUIRE(qpdbiter->node != NULL); 44109689912eSchristos 44119689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS) { 44129689912eSchristos return qpdbiter->result; 44139689912eSchristos } 44149689912eSchristos 44159689912eSchristos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 44169689912eSchristos 44179689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 44189689912eSchristos (void **)&qpdbiter->node, NULL); 44199689912eSchristos 44209689912eSchristos if (qpdbiter->current == &qpdbiter->nsec3iter) { 44219689912eSchristos if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { 44229689912eSchristos /* 44239689912eSchristos * If we're in the NSEC3 tree, it's empty or 44249689912eSchristos * we've reached the origin, then we're done 44259689912eSchristos * with it. 44269689912eSchristos */ 44279689912eSchristos if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) { 44289689912eSchristos qpdbiter->node = NULL; 44299689912eSchristos result = ISC_R_NOMORE; 44309689912eSchristos } 44319689912eSchristos } 44329689912eSchristos if (result == ISC_R_NOMORE && qpdbiter->nsec3mode == full) { 44339689912eSchristos qpdbiter->current = &qpdbiter->mainiter; 44349689912eSchristos dns_qpiter_init(qpdbiter->tsnap, qpdbiter->current); 44359689912eSchristos result = dns_qpiter_prev(qpdbiter->current, NULL, 44369689912eSchristos (void **)&qpdbiter->node, 44379689912eSchristos NULL); 44389689912eSchristos } 44399689912eSchristos } 44409689912eSchristos 44419689912eSchristos if (result == ISC_R_SUCCESS) { 44429689912eSchristos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 44439689912eSchristos } else { 44449689912eSchristos qpdbiter->node = NULL; 44459689912eSchristos } 44469689912eSchristos 44479689912eSchristos qpdbiter->result = result; 44489689912eSchristos return result; 44499689912eSchristos } 44509689912eSchristos 44519689912eSchristos static isc_result_t 44529689912eSchristos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) { 44539689912eSchristos isc_result_t result; 44549689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 44559689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db; 44569689912eSchristos 44579689912eSchristos REQUIRE(qpdbiter->node != NULL); 44589689912eSchristos 44599689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS) { 44609689912eSchristos return qpdbiter->result; 44619689912eSchristos } 44629689912eSchristos 44639689912eSchristos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 44649689912eSchristos 44659689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 44669689912eSchristos (void **)&qpdbiter->node, NULL); 44679689912eSchristos 44689689912eSchristos if (result == ISC_R_NOMORE && qpdbiter->nsec3mode == full && 44699689912eSchristos qpdbiter->current == &qpdbiter->mainiter) 44709689912eSchristos { 44719689912eSchristos qpdbiter->current = &qpdbiter->nsec3iter; 44729689912eSchristos dns_qpiter_init(qpdbiter->nsnap, qpdbiter->current); 44739689912eSchristos result = dns_qpiter_next(qpdbiter->current, NULL, 44749689912eSchristos (void **)&qpdbiter->node, NULL); 44759689912eSchristos } 44769689912eSchristos 44779689912eSchristos if (result == ISC_R_SUCCESS) { 44789689912eSchristos /* 44799689912eSchristos * If we've just started the NSEC3 tree, 44809689912eSchristos * skip over the origin. 44819689912eSchristos */ 44829689912eSchristos if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) { 44839689912eSchristos switch (qpdbiter->nsec3mode) { 44849689912eSchristos case nsec3only: 44859689912eSchristos case full: 44869689912eSchristos result = dns_qpiter_next( 44879689912eSchristos qpdbiter->current, NULL, 44889689912eSchristos (void **)&qpdbiter->node, NULL); 44899689912eSchristos break; 44909689912eSchristos case nonsec3: 44919689912eSchristos result = ISC_R_NOMORE; 44929689912eSchristos qpdbiter->node = NULL; 44939689912eSchristos break; 44949689912eSchristos default: 44959689912eSchristos UNREACHABLE(); 44969689912eSchristos } 44979689912eSchristos } 44989689912eSchristos } 44999689912eSchristos 45009689912eSchristos if (result == ISC_R_SUCCESS) { 45019689912eSchristos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS); 45029689912eSchristos } else { 45039689912eSchristos qpdbiter->node = NULL; 45049689912eSchristos } 45059689912eSchristos 45069689912eSchristos qpdbiter->result = result; 45079689912eSchristos return result; 45089689912eSchristos } 45099689912eSchristos 45109689912eSchristos static isc_result_t 45119689912eSchristos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, 45129689912eSchristos dns_name_t *name DNS__DB_FLARG) { 45139689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db; 45149689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 45159689912eSchristos qpznode_t *node = qpdbiter->node; 45169689912eSchristos 45179689912eSchristos REQUIRE(qpdbiter->result == ISC_R_SUCCESS); 45189689912eSchristos REQUIRE(qpdbiter->node != NULL); 45199689912eSchristos 45209689912eSchristos if (name != NULL) { 45219689912eSchristos dns_name_copy(&qpdbiter->node->name, name); 45229689912eSchristos } 45239689912eSchristos 45249689912eSchristos newref(qpdb, node DNS__DB_FLARG_PASS); 45259689912eSchristos 45269689912eSchristos *nodep = qpdbiter->node; 45279689912eSchristos 45289689912eSchristos return ISC_R_SUCCESS; 45299689912eSchristos } 45309689912eSchristos 45319689912eSchristos static isc_result_t 45329689912eSchristos dbiterator_pause(dns_dbiterator_t *iterator ISC_ATTR_UNUSED) { 45339689912eSchristos return ISC_R_SUCCESS; 45349689912eSchristos } 45359689912eSchristos 45369689912eSchristos static isc_result_t 45379689912eSchristos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) { 45389689912eSchristos qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator; 45399689912eSchristos 45409689912eSchristos if (qpdbiter->result != ISC_R_SUCCESS) { 45419689912eSchristos return qpdbiter->result; 45429689912eSchristos } 45439689912eSchristos 45449689912eSchristos dns_name_copy(dns_rootname, name); 45459689912eSchristos return ISC_R_SUCCESS; 45469689912eSchristos } 45479689912eSchristos 45489689912eSchristos static isc_result_t 45499689912eSchristos createiterator(dns_db_t *db, unsigned int options, 45509689912eSchristos dns_dbiterator_t **iteratorp) { 45519689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 45529689912eSchristos qpdb_dbiterator_t *iter = NULL; 45539689912eSchristos 45549689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 45559689912eSchristos 45569689912eSchristos iter = isc_mem_get(qpdb->common.mctx, sizeof(*iter)); 45579689912eSchristos *iter = (qpdb_dbiterator_t){ 45589689912eSchristos .common.magic = DNS_DBITERATOR_MAGIC, 45599689912eSchristos .common.methods = &dbiterator_methods, 45609689912eSchristos .common.relative_names = ((options & DNS_DB_RELATIVENAMES) != 45619689912eSchristos 0), 45629689912eSchristos }; 45639689912eSchristos 45649689912eSchristos if ((options & DNS_DB_NSEC3ONLY) != 0) { 45659689912eSchristos iter->nsec3mode = nsec3only; 45669689912eSchristos iter->current = &iter->nsec3iter; 45679689912eSchristos } else if ((options & DNS_DB_NONSEC3) != 0) { 45689689912eSchristos iter->nsec3mode = nonsec3; 45699689912eSchristos iter->current = &iter->mainiter; 45709689912eSchristos } else { 45719689912eSchristos iter->nsec3mode = full; 45729689912eSchristos iter->current = &iter->mainiter; 45739689912eSchristos } 45749689912eSchristos 45759689912eSchristos dns_db_attach(db, &iter->common.db); 45769689912eSchristos 45779689912eSchristos dns_qpmulti_snapshot(qpdb->tree, &iter->tsnap); 45789689912eSchristos dns_qpiter_init(iter->tsnap, &iter->mainiter); 45799689912eSchristos 45809689912eSchristos dns_qpmulti_snapshot(qpdb->nsec3, &iter->nsnap); 45819689912eSchristos dns_qpiter_init(iter->nsnap, &iter->nsec3iter); 45829689912eSchristos 45839689912eSchristos *iteratorp = (dns_dbiterator_t *)iter; 45849689912eSchristos return ISC_R_SUCCESS; 45859689912eSchristos } 45869689912eSchristos 45879689912eSchristos static isc_result_t 45889689912eSchristos addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, 45899689912eSchristos isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset, 45909689912eSchristos unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) { 45919689912eSchristos isc_result_t result; 45929689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 45939689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 45949689912eSchristos qpz_version_t *version = dbversion; 45959689912eSchristos isc_region_t region; 45969689912eSchristos dns_slabheader_t *newheader = NULL; 45979689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 45989689912eSchristos dns_fixedname_t fn; 45999689912eSchristos dns_name_t *name = dns_fixedname_initname(&fn); 46009689912eSchristos dns_qp_t *nsec = NULL; 46019689912eSchristos 46029689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 46039689912eSchristos REQUIRE(version != NULL && version->qpdb == qpdb); 46049689912eSchristos 46059689912eSchristos /* 46069689912eSchristos * SOA records are only allowed at top of zone. 46079689912eSchristos */ 46089689912eSchristos if (rdataset->type == dns_rdatatype_soa && node != qpdb->origin) { 46099689912eSchristos return DNS_R_NOTZONETOP; 46109689912eSchristos } 46119689912eSchristos 46129689912eSchristos REQUIRE((node->nsec == DNS_DB_NSEC_NSEC3 && 46139689912eSchristos (rdataset->type == dns_rdatatype_nsec3 || 46149689912eSchristos rdataset->covers == dns_rdatatype_nsec3)) || 46159689912eSchristos (node->nsec != DNS_DB_NSEC_NSEC3 && 46169689912eSchristos rdataset->type != dns_rdatatype_nsec3 && 46179689912eSchristos rdataset->covers != dns_rdatatype_nsec3)); 46189689912eSchristos 46199689912eSchristos result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, 46209689912eSchristos ®ion, sizeof(dns_slabheader_t), 46219689912eSchristos qpdb->maxrrperset); 46229689912eSchristos if (result != ISC_R_SUCCESS) { 46239689912eSchristos if (result == DNS_R_TOOMANYRECORDS) { 46249689912eSchristos dns__db_logtoomanyrecords((dns_db_t *)qpdb, &node->name, 46259689912eSchristos rdataset->type, "adding", 46269689912eSchristos qpdb->maxrrperset); 46279689912eSchristos } 46289689912eSchristos return result; 46299689912eSchristos } 46309689912eSchristos 46319689912eSchristos dns_name_copy(&node->name, name); 46329689912eSchristos dns_rdataset_getownercase(rdataset, name); 46339689912eSchristos 46349689912eSchristos newheader = (dns_slabheader_t *)region.base; 46359689912eSchristos *newheader = (dns_slabheader_t){ 46369689912eSchristos .type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers), 46379689912eSchristos .trust = rdataset->trust, 46389689912eSchristos .node = node, 46399689912eSchristos }; 46409689912eSchristos 46419689912eSchristos dns_slabheader_reset(newheader, db, node); 46429689912eSchristos newheader->ttl = rdataset->ttl; 46439689912eSchristos if (rdataset->ttl == 0U) { 46449689912eSchristos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL); 46459689912eSchristos } 46469689912eSchristos atomic_init(&newheader->count, 46479689912eSchristos atomic_fetch_add_relaxed(&init_count, 1)); 46489689912eSchristos 46499689912eSchristos newheader->serial = version->serial; 46509689912eSchristos if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { 46519689912eSchristos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); 46529689912eSchristos newheader->resign = 46539689912eSchristos (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 46549689912eSchristos 1); 46559689912eSchristos newheader->resign_lsb = rdataset->resign & 0x1; 46569689912eSchristos } 46579689912eSchristos 46589689912eSchristos /* 46599689912eSchristos * Add to the auxiliary NSEC tree if we're adding an NSEC record. 46609689912eSchristos */ 46619689912eSchristos if (node->nsec != DNS_DB_NSEC_HAS_NSEC && 46629689912eSchristos rdataset->type == dns_rdatatype_nsec) 46639689912eSchristos { 46649689912eSchristos dns_qpmulti_write(qpdb->nsec, &nsec); 46659689912eSchristos } 46669689912eSchristos 46679689912eSchristos /* 46689689912eSchristos * If we're adding a delegation type or adding to the auxiliary NSEC 46699689912eSchristos * tree hold an exclusive lock on the tree. In the latter case the 46709689912eSchristos * lock does not necessarily have to be acquired but it will help 46719689912eSchristos * purge ancient entries more effectively. 46729689912eSchristos * 46739689912eSchristos * (Note: node lock must be acquired after starting 46749689912eSchristos * the QPDB transaction and released before committing.) 46759689912eSchristos */ 46769689912eSchristos NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 46779689912eSchristos 46789689912eSchristos result = ISC_R_SUCCESS; 46799689912eSchristos if (nsec != NULL) { 46809689912eSchristos qpznode_t *nsecnode = new_qpznode(qpdb, name); 46819689912eSchristos result = dns_qp_insert(nsec, nsecnode, 0); 46829689912eSchristos if (result == ISC_R_SUCCESS) { 46839689912eSchristos nsecnode->nsec = DNS_DB_NSEC_NSEC; 46849689912eSchristos node->nsec = DNS_DB_NSEC_HAS_NSEC; 46859689912eSchristos } else if (result == ISC_R_EXISTS) { 46869689912eSchristos node->nsec = DNS_DB_NSEC_HAS_NSEC; 46879689912eSchristos result = ISC_R_SUCCESS; 46889689912eSchristos } 46899689912eSchristos qpznode_detach(&nsecnode); 46909689912eSchristos } 46919689912eSchristos 46929689912eSchristos if (result == ISC_R_SUCCESS) { 46939689912eSchristos result = add(qpdb, node, name, version, newheader, options, 46949689912eSchristos false, addedrdataset, 0 DNS__DB_FLARG_PASS); 46959689912eSchristos } 46969689912eSchristos 46979689912eSchristos /* 46989689912eSchristos * If we're adding a delegation type (e.g. NS or DNAME), 46999689912eSchristos * then we need to set the callback bit on the node. 47009689912eSchristos */ 47019689912eSchristos if (result == ISC_R_SUCCESS && 47029689912eSchristos delegating_type(qpdb, node, rdataset->type)) 47039689912eSchristos { 47049689912eSchristos node->delegating = true; 47059689912eSchristos } 47069689912eSchristos 47079689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 47089689912eSchristos 47099689912eSchristos if (nsec != NULL) { 47109689912eSchristos dns_qpmulti_commit(qpdb->nsec, &nsec); 47119689912eSchristos } 47129689912eSchristos 47139689912eSchristos return result; 47149689912eSchristos } 47159689912eSchristos 47169689912eSchristos static isc_result_t 47179689912eSchristos subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, 47189689912eSchristos dns_rdataset_t *rdataset, unsigned int options, 47199689912eSchristos dns_rdataset_t *newrdataset DNS__DB_FLARG) { 47209689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 47219689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 47229689912eSchristos qpz_version_t *version = dbversion; 47239689912eSchristos dns_fixedname_t fname; 47249689912eSchristos dns_name_t *nodename = dns_fixedname_initname(&fname); 47259689912eSchristos dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; 47269689912eSchristos dns_slabheader_t *header = NULL, *newheader = NULL; 47279689912eSchristos unsigned char *subresult = NULL; 47289689912eSchristos isc_region_t region; 47299689912eSchristos isc_result_t result; 47309689912eSchristos qpz_changed_t *changed = NULL; 47319689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 47329689912eSchristos 47339689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 47349689912eSchristos REQUIRE(version != NULL && version->qpdb == qpdb); 47359689912eSchristos 47369689912eSchristos REQUIRE((node->nsec == DNS_DB_NSEC_NSEC3 && 47379689912eSchristos (rdataset->type == dns_rdatatype_nsec3 || 47389689912eSchristos rdataset->covers == dns_rdatatype_nsec3)) || 47399689912eSchristos (node->nsec != DNS_DB_NSEC_NSEC3 && 47409689912eSchristos rdataset->type != dns_rdatatype_nsec3 && 47419689912eSchristos rdataset->covers != dns_rdatatype_nsec3)); 47429689912eSchristos 47439689912eSchristos dns_name_copy(&node->name, nodename); 47449689912eSchristos result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx, 47459689912eSchristos ®ion, sizeof(dns_slabheader_t), 47469689912eSchristos 0); 47479689912eSchristos if (result != ISC_R_SUCCESS) { 47489689912eSchristos return result; 47499689912eSchristos } 47509689912eSchristos 47519689912eSchristos newheader = (dns_slabheader_t *)region.base; 47529689912eSchristos dns_slabheader_reset(newheader, db, node); 47539689912eSchristos newheader->ttl = rdataset->ttl; 47549689912eSchristos newheader->type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers); 47559689912eSchristos atomic_init(&newheader->attributes, 0); 47569689912eSchristos newheader->serial = version->serial; 47579689912eSchristos newheader->trust = 0; 47589689912eSchristos newheader->noqname = NULL; 47599689912eSchristos newheader->closest = NULL; 47609689912eSchristos atomic_init(&newheader->count, 47619689912eSchristos atomic_fetch_add_relaxed(&init_count, 1)); 47629689912eSchristos newheader->last_used = 0; 47639689912eSchristos newheader->node = node; 47649689912eSchristos newheader->db = (dns_db_t *)qpdb; 47659689912eSchristos if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { 47669689912eSchristos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); 47679689912eSchristos newheader->resign = 47689689912eSchristos (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 47699689912eSchristos 1); 47709689912eSchristos newheader->resign_lsb = rdataset->resign & 0x1; 47719689912eSchristos } else { 47729689912eSchristos newheader->resign = 0; 47739689912eSchristos newheader->resign_lsb = 0; 47749689912eSchristos } 47759689912eSchristos 47769689912eSchristos NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 47779689912eSchristos 47789689912eSchristos changed = add_changed(newheader, version DNS__DB_FLARG_PASS); 47799689912eSchristos for (topheader = node->data; topheader != NULL; 47809689912eSchristos topheader = topheader->next) 47819689912eSchristos { 47829689912eSchristos if (topheader->type == newheader->type) { 47839689912eSchristos break; 47849689912eSchristos } 47859689912eSchristos topheader_prev = topheader; 47869689912eSchristos } 47879689912eSchristos /* 47889689912eSchristos * If header isn't NULL, we've found the right type. There may be 47899689912eSchristos * IGNORE rdatasets between the top of the chain and the first real 47909689912eSchristos * data. We skip over them. 47919689912eSchristos */ 47929689912eSchristos header = topheader; 47939689912eSchristos while (header != NULL && IGNORE(header)) { 47949689912eSchristos header = header->down; 47959689912eSchristos } 47969689912eSchristos if (header != NULL && !NONEXISTENT(header)) { 47979689912eSchristos unsigned int flags = 0; 47989689912eSchristos subresult = NULL; 47999689912eSchristos result = ISC_R_SUCCESS; 48009689912eSchristos if ((options & DNS_DBSUB_EXACT) != 0) { 48019689912eSchristos flags |= DNS_RDATASLAB_EXACT; 48029689912eSchristos if (newheader->ttl != header->ttl) { 48039689912eSchristos result = DNS_R_NOTEXACT; 48049689912eSchristos } 48059689912eSchristos } 48069689912eSchristos if (result == ISC_R_SUCCESS) { 48079689912eSchristos result = dns_rdataslab_subtract( 48089689912eSchristos (unsigned char *)header, 48099689912eSchristos (unsigned char *)newheader, 48109689912eSchristos (unsigned int)(sizeof(*newheader)), 48119689912eSchristos qpdb->common.mctx, qpdb->common.rdclass, 48129689912eSchristos (dns_rdatatype_t)header->type, flags, 48139689912eSchristos &subresult); 48149689912eSchristos } 48159689912eSchristos if (result == ISC_R_SUCCESS) { 48169689912eSchristos dns_slabheader_destroy(&newheader); 48179689912eSchristos newheader = (dns_slabheader_t *)subresult; 48189689912eSchristos dns_slabheader_reset(newheader, db, node); 48199689912eSchristos dns_slabheader_copycase(newheader, header); 48209689912eSchristos if (RESIGN(header)) { 48219689912eSchristos DNS_SLABHEADER_SETATTR( 48229689912eSchristos newheader, DNS_SLABHEADERATTR_RESIGN); 48239689912eSchristos newheader->resign = header->resign; 48249689912eSchristos newheader->resign_lsb = header->resign_lsb; 48259689912eSchristos resigninsert(qpdb, newheader); 48269689912eSchristos } 48279689912eSchristos /* 48289689912eSchristos * We have to set the serial since the rdataslab 48299689912eSchristos * subtraction routine copies the reserved portion of 48309689912eSchristos * header, not newheader. 48319689912eSchristos */ 48329689912eSchristos newheader->serial = version->serial; 48339689912eSchristos /* 48349689912eSchristos * XXXJT: dns_rdataslab_subtract() copied the pointers 48359689912eSchristos * to additional info. We need to clear these fields 48369689912eSchristos * to avoid having duplicated references. 48379689912eSchristos */ 48389689912eSchristos maybe_update_recordsandsize(true, version, newheader, 48399689912eSchristos nodename->length); 48409689912eSchristos } else if (result == DNS_R_NXRRSET) { 48419689912eSchristos /* 48429689912eSchristos * This subtraction would remove all of the rdata; 48439689912eSchristos * add a nonexistent header instead. 48449689912eSchristos */ 48459689912eSchristos dns_slabheader_destroy(&newheader); 48469689912eSchristos newheader = dns_slabheader_new((dns_db_t *)qpdb, 48479689912eSchristos (dns_dbnode_t *)node); 48489689912eSchristos newheader->ttl = 0; 48499689912eSchristos newheader->type = topheader->type; 48509689912eSchristos atomic_init(&newheader->attributes, 48519689912eSchristos DNS_SLABHEADERATTR_NONEXISTENT); 48529689912eSchristos newheader->serial = version->serial; 48539689912eSchristos } else { 48549689912eSchristos dns_slabheader_destroy(&newheader); 48559689912eSchristos goto unlock; 48569689912eSchristos } 48579689912eSchristos 48589689912eSchristos /* 48599689912eSchristos * If we're here, we want to link newheader in front of 48609689912eSchristos * topheader. 48619689912eSchristos */ 48629689912eSchristos INSIST(version->serial >= topheader->serial); 48639689912eSchristos maybe_update_recordsandsize(false, version, header, 48649689912eSchristos nodename->length); 48659689912eSchristos if (topheader_prev != NULL) { 48669689912eSchristos topheader_prev->next = newheader; 48679689912eSchristos } else { 48689689912eSchristos node->data = newheader; 48699689912eSchristos } 48709689912eSchristos newheader->next = topheader->next; 48719689912eSchristos newheader->down = topheader; 48729689912eSchristos topheader->next = newheader; 48739689912eSchristos node->dirty = true; 48749689912eSchristos changed->dirty = true; 48759689912eSchristos resigndelete(qpdb, version, header DNS__DB_FLARG_PASS); 48769689912eSchristos } else { 48779689912eSchristos /* 48789689912eSchristos * The rdataset doesn't exist, so we don't need to do anything 48799689912eSchristos * to satisfy the deletion request. 48809689912eSchristos */ 48819689912eSchristos dns_slabheader_destroy(&newheader); 48829689912eSchristos if ((options & DNS_DBSUB_EXACT) != 0) { 48839689912eSchristos result = DNS_R_NOTEXACT; 48849689912eSchristos } else { 48859689912eSchristos result = DNS_R_UNCHANGED; 48869689912eSchristos } 48879689912eSchristos } 48889689912eSchristos 48899689912eSchristos if (result == ISC_R_SUCCESS && newrdataset != NULL) { 48909689912eSchristos bindrdataset(qpdb, node, newheader, 0, 48919689912eSchristos newrdataset DNS__DB_FLARG_PASS); 48929689912eSchristos } 48939689912eSchristos 48949689912eSchristos if (result == DNS_R_NXRRSET && newrdataset != NULL && 48959689912eSchristos (options & DNS_DBSUB_WANTOLD) != 0) 48969689912eSchristos { 48979689912eSchristos bindrdataset(qpdb, node, header, 0, 48989689912eSchristos newrdataset DNS__DB_FLARG_PASS); 48999689912eSchristos } 49009689912eSchristos 49019689912eSchristos unlock: 49029689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 49039689912eSchristos return result; 49049689912eSchristos } 49059689912eSchristos 49069689912eSchristos static isc_result_t 49079689912eSchristos deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, 49089689912eSchristos dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) { 49099689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 49109689912eSchristos qpznode_t *node = (qpznode_t *)dbnode; 49119689912eSchristos qpz_version_t *version = dbversion; 49129689912eSchristos dns_fixedname_t fname; 49139689912eSchristos dns_name_t *nodename = dns_fixedname_initname(&fname); 49149689912eSchristos isc_result_t result; 49159689912eSchristos dns_slabheader_t *newheader = NULL; 49169689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 49179689912eSchristos 49189689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 49199689912eSchristos REQUIRE(version != NULL && version->qpdb == qpdb); 49209689912eSchristos 49219689912eSchristos if (type == dns_rdatatype_any) { 49229689912eSchristos return ISC_R_NOTIMPLEMENTED; 49239689912eSchristos } 49249689912eSchristos if (type == dns_rdatatype_rrsig && covers == 0) { 49259689912eSchristos return ISC_R_NOTIMPLEMENTED; 49269689912eSchristos } 49279689912eSchristos 49289689912eSchristos newheader = dns_slabheader_new(db, node); 49299689912eSchristos newheader->type = DNS_TYPEPAIR_VALUE(type, covers); 49309689912eSchristos newheader->ttl = 0; 49319689912eSchristos atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); 49329689912eSchristos newheader->serial = version->serial; 49339689912eSchristos 49349689912eSchristos dns_name_copy(&node->name, nodename); 49359689912eSchristos 49369689912eSchristos NODE_WRLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 49379689912eSchristos result = add(qpdb, node, nodename, version, newheader, DNS_DBADD_FORCE, 49389689912eSchristos false, NULL, 0 DNS__DB_FLARG_PASS); 49399689912eSchristos NODE_UNLOCK(&qpdb->node_locks[node->locknum].lock, &nlocktype); 49409689912eSchristos return result; 49419689912eSchristos } 49429689912eSchristos 49439689912eSchristos static isc_result_t 49449689912eSchristos nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { 49459689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 49469689912eSchristos qpznode_t *qpnode = (qpznode_t *)node; 49479689912eSchristos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 49489689912eSchristos 49499689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 49509689912eSchristos REQUIRE(node != NULL); 49519689912eSchristos REQUIRE(name != NULL); 49529689912eSchristos 49539689912eSchristos NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); 49549689912eSchristos dns_name_copy(&qpnode->name, name); 49559689912eSchristos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype); 49569689912eSchristos return ISC_R_SUCCESS; 49579689912eSchristos } 49589689912eSchristos 49599689912eSchristos static dns_glue_t * 49609689912eSchristos new_gluelist(isc_mem_t *mctx, dns_name_t *name) { 49619689912eSchristos dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue)); 49629689912eSchristos *glue = (dns_glue_t){ 0 }; 49639689912eSchristos dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname); 49649689912eSchristos 49659689912eSchristos dns_name_copy(name, gluename); 49669689912eSchristos 49679689912eSchristos return glue; 49689689912eSchristos } 49699689912eSchristos 49709689912eSchristos static isc_result_t 49719689912eSchristos glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 49729689912eSchristos dns_rdataset_t *unused DNS__DB_FLARG) { 49739689912eSchristos dns_glue_additionaldata_ctx_t *ctx = NULL; 49749689912eSchristos isc_result_t result; 49759689912eSchristos dns_fixedname_t fixedname_a; 49769689912eSchristos dns_name_t *name_a = NULL; 49779689912eSchristos dns_rdataset_t rdataset_a, sigrdataset_a; 49789689912eSchristos qpznode_t *node_a = NULL; 49799689912eSchristos dns_fixedname_t fixedname_aaaa; 49809689912eSchristos dns_name_t *name_aaaa = NULL; 49819689912eSchristos dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa; 49829689912eSchristos qpznode_t *node_aaaa = NULL; 49839689912eSchristos dns_glue_t *glue = NULL; 49849689912eSchristos 49859689912eSchristos UNUSED(unused); 49869689912eSchristos 49879689912eSchristos /* 49889689912eSchristos * NS records want addresses in additional records. 49899689912eSchristos */ 49909689912eSchristos INSIST(qtype == dns_rdatatype_a); 49919689912eSchristos 49929689912eSchristos ctx = (dns_glue_additionaldata_ctx_t *)arg; 49939689912eSchristos 49949689912eSchristos name_a = dns_fixedname_initname(&fixedname_a); 49959689912eSchristos dns_rdataset_init(&rdataset_a); 49969689912eSchristos dns_rdataset_init(&sigrdataset_a); 49979689912eSchristos 49989689912eSchristos name_aaaa = dns_fixedname_initname(&fixedname_aaaa); 49999689912eSchristos dns_rdataset_init(&rdataset_aaaa); 50009689912eSchristos dns_rdataset_init(&sigrdataset_aaaa); 50019689912eSchristos 50029689912eSchristos result = find(ctx->db, name, ctx->version, dns_rdatatype_a, 50039689912eSchristos DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a, 50049689912eSchristos &rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS); 50059689912eSchristos if (result == DNS_R_GLUE) { 50069689912eSchristos glue = new_gluelist(ctx->db->mctx, name_a); 50079689912eSchristos 50089689912eSchristos dns_rdataset_init(&glue->rdataset_a); 50099689912eSchristos dns_rdataset_init(&glue->sigrdataset_a); 50109689912eSchristos dns_rdataset_init(&glue->rdataset_aaaa); 50119689912eSchristos dns_rdataset_init(&glue->sigrdataset_aaaa); 50129689912eSchristos 50139689912eSchristos dns_rdataset_clone(&rdataset_a, &glue->rdataset_a); 50149689912eSchristos if (dns_rdataset_isassociated(&sigrdataset_a)) { 50159689912eSchristos dns_rdataset_clone(&sigrdataset_a, 50169689912eSchristos &glue->sigrdataset_a); 50179689912eSchristos } 50189689912eSchristos } 50199689912eSchristos 50209689912eSchristos result = find(ctx->db, name, ctx->version, dns_rdatatype_aaaa, 50219689912eSchristos DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa, 50229689912eSchristos name_aaaa, &rdataset_aaaa, 50239689912eSchristos &sigrdataset_aaaa DNS__DB_FLARG_PASS); 50249689912eSchristos if (result == DNS_R_GLUE) { 50259689912eSchristos if (glue == NULL) { 50269689912eSchristos glue = new_gluelist(ctx->db->mctx, name_aaaa); 50279689912eSchristos 50289689912eSchristos dns_rdataset_init(&glue->rdataset_a); 50299689912eSchristos dns_rdataset_init(&glue->sigrdataset_a); 50309689912eSchristos dns_rdataset_init(&glue->rdataset_aaaa); 50319689912eSchristos dns_rdataset_init(&glue->sigrdataset_aaaa); 50329689912eSchristos } else { 50339689912eSchristos INSIST(node_a == node_aaaa); 50349689912eSchristos INSIST(dns_name_equal(name_a, name_aaaa)); 50359689912eSchristos } 50369689912eSchristos 50379689912eSchristos dns_rdataset_clone(&rdataset_aaaa, &glue->rdataset_aaaa); 50389689912eSchristos if (dns_rdataset_isassociated(&sigrdataset_aaaa)) { 50399689912eSchristos dns_rdataset_clone(&sigrdataset_aaaa, 50409689912eSchristos &glue->sigrdataset_aaaa); 50419689912eSchristos } 50429689912eSchristos } 50439689912eSchristos 50449689912eSchristos /* 50459689912eSchristos * If the currently processed NS record is in-bailiwick, mark any glue 50469689912eSchristos * RRsets found for it with DNS_RDATASETATTR_REQUIRED. Note that for 50479689912eSchristos * simplicity, glue RRsets for all in-bailiwick NS records are marked 50489689912eSchristos * this way, even though dns_message_rendersection() only checks the 50499689912eSchristos * attributes for the first rdataset associated with the first name 50509689912eSchristos * added to the ADDITIONAL section. 50519689912eSchristos */ 50529689912eSchristos if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) { 50539689912eSchristos if (dns_rdataset_isassociated(&glue->rdataset_a)) { 50549689912eSchristos glue->rdataset_a.attributes |= 50559689912eSchristos DNS_RDATASETATTR_REQUIRED; 50569689912eSchristos } 50579689912eSchristos if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { 50589689912eSchristos glue->rdataset_aaaa.attributes |= 50599689912eSchristos DNS_RDATASETATTR_REQUIRED; 50609689912eSchristos } 50619689912eSchristos } 50629689912eSchristos 50639689912eSchristos if (glue != NULL) { 50649689912eSchristos glue->next = ctx->glue_list; 50659689912eSchristos ctx->glue_list = glue; 50669689912eSchristos } 50679689912eSchristos 50689689912eSchristos result = ISC_R_SUCCESS; 50699689912eSchristos 50709689912eSchristos if (dns_rdataset_isassociated(&rdataset_a)) { 50719689912eSchristos dns_rdataset_disassociate(&rdataset_a); 50729689912eSchristos } 50739689912eSchristos if (dns_rdataset_isassociated(&sigrdataset_a)) { 50749689912eSchristos dns_rdataset_disassociate(&sigrdataset_a); 50759689912eSchristos } 50769689912eSchristos 50779689912eSchristos if (dns_rdataset_isassociated(&rdataset_aaaa)) { 50789689912eSchristos dns_rdataset_disassociate(&rdataset_aaaa); 50799689912eSchristos } 50809689912eSchristos if (dns_rdataset_isassociated(&sigrdataset_aaaa)) { 50819689912eSchristos dns_rdataset_disassociate(&sigrdataset_aaaa); 50829689912eSchristos } 50839689912eSchristos 50849689912eSchristos if (node_a != NULL) { 50859689912eSchristos dns__db_detachnode(ctx->db, 50869689912eSchristos (dns_dbnode_t *)&node_a DNS__DB_FLARG_PASS); 50879689912eSchristos } 50889689912eSchristos if (node_aaaa != NULL) { 50899689912eSchristos dns__db_detachnode( 50909689912eSchristos ctx->db, (dns_dbnode_t *)&node_aaaa DNS__DB_FLARG_PASS); 50919689912eSchristos } 50929689912eSchristos 50939689912eSchristos return result; 50949689912eSchristos } 50959689912eSchristos 50969689912eSchristos #define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0) 50979689912eSchristos 50989689912eSchristos static void 50999689912eSchristos addglue_to_message(dns_glue_t *ge, dns_message_t *msg) { 51009689912eSchristos for (; ge != NULL; ge = ge->next) { 51019689912eSchristos dns_name_t *name = NULL; 51029689912eSchristos dns_rdataset_t *rdataset_a = NULL; 51039689912eSchristos dns_rdataset_t *sigrdataset_a = NULL; 51049689912eSchristos dns_rdataset_t *rdataset_aaaa = NULL; 51059689912eSchristos dns_rdataset_t *sigrdataset_aaaa = NULL; 51069689912eSchristos dns_name_t *gluename = dns_fixedname_name(&ge->fixedname); 51079689912eSchristos bool prepend_name = false; 51089689912eSchristos 51099689912eSchristos dns_message_gettempname(msg, &name); 51109689912eSchristos 51119689912eSchristos dns_name_copy(gluename, name); 51129689912eSchristos 51139689912eSchristos if (dns_rdataset_isassociated(&ge->rdataset_a)) { 51149689912eSchristos dns_message_gettemprdataset(msg, &rdataset_a); 51159689912eSchristos } 51169689912eSchristos 51179689912eSchristos if (dns_rdataset_isassociated(&ge->sigrdataset_a)) { 51189689912eSchristos dns_message_gettemprdataset(msg, &sigrdataset_a); 51199689912eSchristos } 51209689912eSchristos 51219689912eSchristos if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) { 51229689912eSchristos dns_message_gettemprdataset(msg, &rdataset_aaaa); 51239689912eSchristos } 51249689912eSchristos 51259689912eSchristos if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) { 51269689912eSchristos dns_message_gettemprdataset(msg, &sigrdataset_aaaa); 51279689912eSchristos } 51289689912eSchristos 51299689912eSchristos if (rdataset_a != NULL) { 51309689912eSchristos dns_rdataset_clone(&ge->rdataset_a, rdataset_a); 51319689912eSchristos ISC_LIST_APPEND(name->list, rdataset_a, link); 51329689912eSchristos if (IS_REQUIRED_GLUE(rdataset_a)) { 51339689912eSchristos prepend_name = true; 51349689912eSchristos } 51359689912eSchristos } 51369689912eSchristos 51379689912eSchristos if (sigrdataset_a != NULL) { 51389689912eSchristos dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a); 51399689912eSchristos ISC_LIST_APPEND(name->list, sigrdataset_a, link); 51409689912eSchristos } 51419689912eSchristos 51429689912eSchristos if (rdataset_aaaa != NULL) { 51439689912eSchristos dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa); 51449689912eSchristos ISC_LIST_APPEND(name->list, rdataset_aaaa, link); 51459689912eSchristos if (IS_REQUIRED_GLUE(rdataset_aaaa)) { 51469689912eSchristos prepend_name = true; 51479689912eSchristos } 51489689912eSchristos } 51499689912eSchristos if (sigrdataset_aaaa != NULL) { 51509689912eSchristos dns_rdataset_clone(&ge->sigrdataset_aaaa, 51519689912eSchristos sigrdataset_aaaa); 51529689912eSchristos ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link); 51539689912eSchristos } 51549689912eSchristos 51559689912eSchristos dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); 51569689912eSchristos 51579689912eSchristos /* 51589689912eSchristos * When looking for required glue, dns_message_rendersection() 51599689912eSchristos * only processes the first rdataset associated with the first 51609689912eSchristos * name added to the ADDITIONAL section. dns_message_addname() 51619689912eSchristos * performs an append on the list of names in a given section, 51629689912eSchristos * so if any glue record was marked as required, we need to 51639689912eSchristos * move the name it is associated with to the beginning of the 51649689912eSchristos * list for the ADDITIONAL section or else required glue might 51659689912eSchristos * not be rendered. 51669689912eSchristos */ 51679689912eSchristos if (prepend_name) { 51689689912eSchristos ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL], 51699689912eSchristos name, link); 51709689912eSchristos ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL], 51719689912eSchristos name, link); 51729689912eSchristos } 51739689912eSchristos } 51749689912eSchristos } 51759689912eSchristos 51769689912eSchristos static dns_glue_t * 51779689912eSchristos newglue(dns_db_t *db, qpz_version_t *version, qpznode_t *node, 51789689912eSchristos dns_rdataset_t *rdataset) { 51799689912eSchristos dns_fixedname_t nodename; 51809689912eSchristos dns_glue_additionaldata_ctx_t ctx = { 51819689912eSchristos .db = db, 51829689912eSchristos .version = (dns_dbversion_t *)version, 51839689912eSchristos .nodename = dns_fixedname_initname(&nodename), 51849689912eSchristos }; 51859689912eSchristos 51869689912eSchristos /* 51879689912eSchristos * Get the owner name of the NS RRset - it will be necessary for 51889689912eSchristos * identifying required glue in glue_nsdname_cb() (by 51899689912eSchristos * determining which NS records in the delegation are 51909689912eSchristos * in-bailiwick). 51919689912eSchristos */ 51929689912eSchristos dns_name_copy(&node->name, ctx.nodename); 51939689912eSchristos 51949689912eSchristos (void)dns_rdataset_additionaldata(rdataset, dns_rootname, 51959689912eSchristos glue_nsdname_cb, &ctx); 51969689912eSchristos 51979689912eSchristos return ctx.glue_list; 51989689912eSchristos } 51999689912eSchristos 52009689912eSchristos static dns_gluenode_t * 52019689912eSchristos new_gluenode(dns_db_t *db, qpz_version_t *version, qpznode_t *node, 52029689912eSchristos dns_rdataset_t *rdataset) { 52039689912eSchristos dns_gluenode_t *gluenode = isc_mem_get(db->mctx, sizeof(*gluenode)); 52049689912eSchristos *gluenode = (dns_gluenode_t){ 52059689912eSchristos .glue = newglue(db, version, node, rdataset), 52069689912eSchristos }; 52079689912eSchristos 52089689912eSchristos isc_mem_attach(db->mctx, &gluenode->mctx); 52099689912eSchristos qpznode_attach(node, &gluenode->node); 52109689912eSchristos 52119689912eSchristos return gluenode; 52129689912eSchristos } 52139689912eSchristos 52149689912eSchristos static void 52159689912eSchristos freeglue(isc_mem_t *mctx, dns_glue_t *glue) { 52169689912eSchristos while (glue != NULL) { 52179689912eSchristos dns_glue_t *next = glue->next; 52189689912eSchristos 52199689912eSchristos if (dns_rdataset_isassociated(&glue->rdataset_a)) { 52209689912eSchristos dns_rdataset_disassociate(&glue->rdataset_a); 52219689912eSchristos } 52229689912eSchristos if (dns_rdataset_isassociated(&glue->sigrdataset_a)) { 52239689912eSchristos dns_rdataset_disassociate(&glue->sigrdataset_a); 52249689912eSchristos } 52259689912eSchristos 52269689912eSchristos if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { 52279689912eSchristos dns_rdataset_disassociate(&glue->rdataset_aaaa); 52289689912eSchristos } 52299689912eSchristos if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) { 52309689912eSchristos dns_rdataset_disassociate(&glue->sigrdataset_aaaa); 52319689912eSchristos } 52329689912eSchristos 52339689912eSchristos dns_rdataset_invalidate(&glue->rdataset_a); 52349689912eSchristos dns_rdataset_invalidate(&glue->sigrdataset_a); 52359689912eSchristos dns_rdataset_invalidate(&glue->rdataset_aaaa); 52369689912eSchristos dns_rdataset_invalidate(&glue->sigrdataset_aaaa); 52379689912eSchristos 52389689912eSchristos isc_mem_put(mctx, glue, sizeof(*glue)); 52399689912eSchristos 52409689912eSchristos glue = next; 52419689912eSchristos } 52429689912eSchristos } 52439689912eSchristos 52449689912eSchristos static void 52459689912eSchristos free_gluenode_rcu(struct rcu_head *rcu_head) { 52469689912eSchristos dns_gluenode_t *gluenode = caa_container_of(rcu_head, dns_gluenode_t, 52479689912eSchristos rcu_head); 52489689912eSchristos 52499689912eSchristos freeglue(gluenode->mctx, gluenode->glue); 52509689912eSchristos 52519689912eSchristos qpznode_detach(&gluenode->node); 52529689912eSchristos 52539689912eSchristos isc_mem_putanddetach(&gluenode->mctx, gluenode, sizeof(*gluenode)); 52549689912eSchristos } 52559689912eSchristos 52569689912eSchristos static void 52579689912eSchristos free_gluenode(dns_gluenode_t *gluenode) { 52589689912eSchristos call_rcu(&gluenode->rcu_head, free_gluenode_rcu); 52599689912eSchristos } 52609689912eSchristos 52619689912eSchristos static uint32_t 52629689912eSchristos qpznode_hash(const qpznode_t *node) { 52639689912eSchristos return isc_hash32(&node, sizeof(node), true); 52649689912eSchristos } 52659689912eSchristos 52669689912eSchristos static int 52679689912eSchristos qpznode_match(struct cds_lfht_node *ht_node, const void *key) { 52689689912eSchristos const dns_gluenode_t *gluenode = 52699689912eSchristos caa_container_of(ht_node, dns_gluenode_t, ht_node); 52709689912eSchristos const qpznode_t *node = key; 52719689912eSchristos 52729689912eSchristos return gluenode->node == node; 52739689912eSchristos } 52749689912eSchristos 52759689912eSchristos static uint32_t 52769689912eSchristos gluenode_hash(const dns_gluenode_t *gluenode) { 52779689912eSchristos return qpznode_hash(gluenode->node); 52789689912eSchristos } 52799689912eSchristos 52809689912eSchristos static int 52819689912eSchristos gluenode_match(struct cds_lfht_node *ht_node, const void *key) { 52829689912eSchristos const dns_gluenode_t *gluenode = key; 52839689912eSchristos 52849689912eSchristos return qpznode_match(ht_node, gluenode->node); 52859689912eSchristos } 52869689912eSchristos 52879689912eSchristos static void 52889689912eSchristos addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset, 52899689912eSchristos dns_message_t *msg) { 52909689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 52919689912eSchristos qpz_version_t *version = dbversion; 52929689912eSchristos qpznode_t *node = (qpznode_t *)rdataset->slab.node; 52939689912eSchristos dns_gluenode_t *gluenode = NULL; 52949689912eSchristos 52959689912eSchristos REQUIRE(rdataset->type == dns_rdatatype_ns); 52969689912eSchristos REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db); 52979689912eSchristos REQUIRE(qpdb == version->qpdb); 52989689912eSchristos REQUIRE(!IS_STUB(qpdb)); 52999689912eSchristos 53009689912eSchristos /* 53019689912eSchristos * The glue table cache that forms a part of the DB version 53029689912eSchristos * structure is not explicitly bounded and there's no cache 53039689912eSchristos * cleaning. The zone data size itself is an implicit bound. 53049689912eSchristos * 53059689912eSchristos * The key into the glue hashtable is the node pointer. This is 53069689912eSchristos * because the glue hashtable is a property of the DB version, 53079689912eSchristos * and the glue is keyed for the ownername/NS tuple. We don't 53089689912eSchristos * bother with using an expensive dns_name_t comparison here as 53099689912eSchristos * the node pointer is a fixed value that won't change for a DB 53109689912eSchristos * version and can be compared directly. 53119689912eSchristos */ 53129689912eSchristos 53139689912eSchristos rcu_read_lock(); 53149689912eSchristos 53159689912eSchristos struct cds_lfht_iter iter; 53169689912eSchristos cds_lfht_lookup(version->glue_table, qpznode_hash(node), qpznode_match, 53179689912eSchristos node, &iter); 53189689912eSchristos 53199689912eSchristos gluenode = cds_lfht_entry(cds_lfht_iter_get_node(&iter), dns_gluenode_t, 53209689912eSchristos ht_node); 53219689912eSchristos if (gluenode == NULL) { 53229689912eSchristos /* No cached glue was found in the table. Get new glue. */ 53239689912eSchristos gluenode = new_gluenode(db, version, node, rdataset); 53249689912eSchristos 53259689912eSchristos struct cds_lfht_node *ht_node = cds_lfht_add_unique( 53269689912eSchristos version->glue_table, gluenode_hash(gluenode), 53279689912eSchristos gluenode_match, gluenode, &gluenode->ht_node); 53289689912eSchristos 53299689912eSchristos if (ht_node != &gluenode->ht_node) { 53309689912eSchristos free_gluenode_rcu(&gluenode->rcu_head); 53319689912eSchristos 53329689912eSchristos gluenode = cds_lfht_entry(ht_node, dns_gluenode_t, 53339689912eSchristos ht_node); 53349689912eSchristos } 53359689912eSchristos } 53369689912eSchristos 53379689912eSchristos INSIST(gluenode != NULL); 53389689912eSchristos 53399689912eSchristos dns_glue_t *glue = gluenode->glue; 53409689912eSchristos isc_statscounter_t counter = dns_gluecachestatscounter_hits_present; 53419689912eSchristos 53429689912eSchristos if (glue != NULL) { 53439689912eSchristos /* We have a cached result. Add it to the message and return. */ 53449689912eSchristos addglue_to_message(glue, msg); 53459689912eSchristos } else { 53469689912eSchristos counter = dns_gluecachestatscounter_hits_absent; 53479689912eSchristos } 53489689912eSchristos 53499689912eSchristos rcu_read_unlock(); 53509689912eSchristos 53519689912eSchristos if (qpdb->gluecachestats != NULL) { 53529689912eSchristos isc_stats_increment(qpdb->gluecachestats, counter); 53539689912eSchristos } 53549689912eSchristos } 53559689912eSchristos 53569689912eSchristos static void 53579689912eSchristos setmaxrrperset(dns_db_t *db, uint32_t value) { 53589689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 53599689912eSchristos 53609689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 53619689912eSchristos 53629689912eSchristos qpdb->maxrrperset = value; 53639689912eSchristos } 53649689912eSchristos 53659689912eSchristos static void 53669689912eSchristos setmaxtypepername(dns_db_t *db, uint32_t value) { 53679689912eSchristos qpzonedb_t *qpdb = (qpzonedb_t *)db; 53689689912eSchristos 53699689912eSchristos REQUIRE(VALID_QPZONE(qpdb)); 53709689912eSchristos 53719689912eSchristos qpdb->maxtypepername = value; 53729689912eSchristos } 53739689912eSchristos 53749689912eSchristos static dns_dbmethods_t qpdb_zonemethods = { 53759689912eSchristos .destroy = qpdb_destroy, 53769689912eSchristos .beginload = beginload, 53779689912eSchristos .endload = endload, 53789689912eSchristos .currentversion = currentversion, 53799689912eSchristos .newversion = newversion, 53809689912eSchristos .attachversion = attachversion, 53819689912eSchristos .closeversion = closeversion, 53829689912eSchristos .findnode = findnode, 53839689912eSchristos .find = find, 53849689912eSchristos .attachnode = attachnode, 53859689912eSchristos .detachnode = detachnode, 53869689912eSchristos .createiterator = createiterator, 53879689912eSchristos .findrdataset = findrdataset, 53889689912eSchristos .allrdatasets = allrdatasets, 53899689912eSchristos .addrdataset = addrdataset, 53909689912eSchristos .subtractrdataset = subtractrdataset, 53919689912eSchristos .deleterdataset = deleterdataset, 53929689912eSchristos .issecure = issecure, 53939689912eSchristos .nodecount = nodecount, 53949689912eSchristos .setloop = setloop, 53959689912eSchristos .getoriginnode = getoriginnode, 53969689912eSchristos .getnsec3parameters = getnsec3parameters, 53979689912eSchristos .findnsec3node = findnsec3node, 53989689912eSchristos .setsigningtime = setsigningtime, 53999689912eSchristos .getsigningtime = getsigningtime, 54009689912eSchristos .getsize = getsize, 54019689912eSchristos .setgluecachestats = setgluecachestats, 54029689912eSchristos .locknode = locknode, 54039689912eSchristos .unlocknode = unlocknode, 54049689912eSchristos .addglue = addglue, 54059689912eSchristos .deletedata = deletedata, 54069689912eSchristos .nodefullname = nodefullname, 54079689912eSchristos .setmaxrrperset = setmaxrrperset, 54089689912eSchristos .setmaxtypepername = setmaxtypepername, 54099689912eSchristos }; 54109689912eSchristos 54119689912eSchristos static void 54129689912eSchristos destroy_qpznode(qpznode_t *node) { 54139689912eSchristos dns_slabheader_t *current = NULL, *next = NULL; 54149689912eSchristos 54159689912eSchristos for (current = node->data; current != NULL; current = next) { 54169689912eSchristos dns_slabheader_t *down = current->down, *down_next = NULL; 54179689912eSchristos 54189689912eSchristos next = current->next; 54199689912eSchristos 54209689912eSchristos for (down = current->down; down != NULL; down = down_next) { 54219689912eSchristos down_next = down->down; 54229689912eSchristos dns_slabheader_destroy(&down); 54239689912eSchristos } 54249689912eSchristos 54259689912eSchristos dns_slabheader_destroy(¤t); 54269689912eSchristos } 54279689912eSchristos 54289689912eSchristos dns_name_free(&node->name, node->mctx); 54299689912eSchristos isc_mem_putanddetach(&node->mctx, node, sizeof(qpznode_t)); 54309689912eSchristos } 54319689912eSchristos 54329689912eSchristos #if DNS_DB_NODETRACE 54339689912eSchristos ISC_REFCOUNT_STATIC_TRACE_IMPL(qpznode, destroy_qpznode); 54349689912eSchristos #else 54359689912eSchristos ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode); 54369689912eSchristos #endif 54379689912eSchristos 54389689912eSchristos static void 54399689912eSchristos qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval, 54409689912eSchristos uint32_t ival ISC_ATTR_UNUSED) { 54419689912eSchristos qpznode_t *data = pval; 54429689912eSchristos qpznode_ref(data); 54439689912eSchristos } 54449689912eSchristos 54459689912eSchristos static void 54469689912eSchristos qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval, 54479689912eSchristos uint32_t ival ISC_ATTR_UNUSED) { 54489689912eSchristos qpznode_t *data = pval; 54499689912eSchristos qpznode_detach(&data); 54509689912eSchristos } 54519689912eSchristos 54529689912eSchristos static size_t 54539689912eSchristos qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval, 54549689912eSchristos uint32_t ival ISC_ATTR_UNUSED) { 54559689912eSchristos qpznode_t *data = pval; 54569689912eSchristos return dns_qpkey_fromname(key, &data->name); 54579689912eSchristos } 54589689912eSchristos 54599689912eSchristos static void 54609689912eSchristos qp_triename(void *uctx ISC_ATTR_UNUSED, char *buf, size_t size) { 54619689912eSchristos snprintf(buf, size, "QPDB"); 54629689912eSchristos } 5463