Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: db.c,v 1.15 2026/05/20 16:53:45 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 /***
     19  *** Imports
     20  ***/
     21 
     22 #include <inttypes.h>
     23 #include <stdbool.h>
     24 
     25 #include <isc/buffer.h>
     26 #include <isc/hash.h>
     27 #include <isc/mem.h>
     28 #include <isc/once.h>
     29 #include <isc/result.h>
     30 #include <isc/rwlock.h>
     31 #include <isc/string.h>
     32 #include <isc/tid.h>
     33 #include <isc/urcu.h>
     34 #include <isc/util.h>
     35 
     36 #include <dns/callbacks.h>
     37 #include <dns/clientinfo.h>
     38 #include <dns/db.h>
     39 #include <dns/dbiterator.h>
     40 #include <dns/log.h>
     41 #include <dns/master.h>
     42 #include <dns/rdata.h>
     43 #include <dns/rdataclass.h>
     44 #include <dns/rdataset.h>
     45 #include <dns/rdatasetiter.h>
     46 #include <dns/rdataslab.h>
     47 #include <dns/stats.h>
     48 
     49 /***
     50  *** Private Types
     51  ***/
     52 
     53 struct dns_dbimplementation {
     54 	const char *name;
     55 	dns_dbcreatefunc_t create;
     56 	isc_mem_t *mctx;
     57 	void *driverarg;
     58 	ISC_LINK(dns_dbimplementation_t) link;
     59 };
     60 
     61 /***
     62  *** Supported DB Implementations Registry
     63  ***/
     64 
     65 /*
     66  * Built in database implementations are registered here.
     67  */
     68 
     69 #include "db_p.h"
     70 #include "qpcache_p.h"
     71 #include "qpzone_p.h"
     72 #include "rbtdb_p.h"
     73 
     74 unsigned int dns_pps = 0U;
     75 
     76 static ISC_LIST(dns_dbimplementation_t) implementations;
     77 static isc_rwlock_t implock;
     78 static isc_once_t once = ISC_ONCE_INIT;
     79 
     80 static dns_dbimplementation_t rbtimp;
     81 static dns_dbimplementation_t qpimp;
     82 static dns_dbimplementation_t qpzoneimp;
     83 
     84 static void
     85 initialize(void) {
     86 	isc_rwlock_init(&implock);
     87 
     88 	ISC_LIST_INIT(implementations);
     89 
     90 	rbtimp = (dns_dbimplementation_t){
     91 		.name = "rbt",
     92 		.create = dns__rbtdb_create,
     93 		.link = ISC_LINK_INITIALIZER,
     94 	};
     95 
     96 	qpimp = (dns_dbimplementation_t){
     97 		.name = "qpcache",
     98 		.create = dns__qpcache_create,
     99 		.link = ISC_LINK_INITIALIZER,
    100 	};
    101 
    102 	qpzoneimp = (dns_dbimplementation_t){
    103 		.name = "qpzone",
    104 		.create = dns__qpzone_create,
    105 		.link = ISC_LINK_INITIALIZER,
    106 	};
    107 
    108 	ISC_LIST_APPEND(implementations, &rbtimp, link);
    109 	ISC_LIST_APPEND(implementations, &qpimp, link);
    110 	ISC_LIST_APPEND(implementations, &qpzoneimp, link);
    111 }
    112 
    113 static dns_dbimplementation_t *
    114 impfind(const char *name) {
    115 	dns_dbimplementation_t *imp;
    116 
    117 	for (imp = ISC_LIST_HEAD(implementations); imp != NULL;
    118 	     imp = ISC_LIST_NEXT(imp, link))
    119 	{
    120 		if (strcasecmp(name, imp->name) == 0) {
    121 			return imp;
    122 		}
    123 	}
    124 	return NULL;
    125 }
    126 
    127 static void
    128 call_updatenotify(dns_db_t *db);
    129 
    130 /***
    131  *** Basic DB Methods
    132  ***/
    133 
    134 isc_result_t
    135 dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin,
    136 	      dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc,
    137 	      char *argv[], dns_db_t **dbp) {
    138 	dns_dbimplementation_t *impinfo = NULL;
    139 
    140 	isc_once_do(&once, initialize);
    141 
    142 	/*
    143 	 * Create a new database using implementation 'db_type'.
    144 	 */
    145 
    146 	REQUIRE(dbp != NULL && *dbp == NULL);
    147 	REQUIRE(dns_name_isabsolute(origin));
    148 
    149 	RWLOCK(&implock, isc_rwlocktype_read);
    150 	impinfo = impfind(db_type);
    151 	if (impinfo != NULL) {
    152 		isc_result_t result;
    153 		result = ((impinfo->create)(mctx, origin, type, rdclass, argc,
    154 					    argv, impinfo->driverarg, dbp));
    155 		RWUNLOCK(&implock, isc_rwlocktype_read);
    156 
    157 #if DNS_DB_TRACE
    158 		fprintf(stderr, "dns_db_create:%s:%s:%d:%p->references = 1\n",
    159 			__func__, __FILE__, __LINE__ + 1, *dbp);
    160 #endif
    161 		return result;
    162 	}
    163 
    164 	RWUNLOCK(&implock, isc_rwlocktype_read);
    165 
    166 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
    167 		      ISC_LOG_ERROR, "unsupported database type '%s'", db_type);
    168 
    169 	return ISC_R_NOTFOUND;
    170 }
    171 
    172 static void
    173 dns__db_destroy(dns_db_t *db) {
    174 	(db->methods->destroy)(db);
    175 }
    176 
    177 #if DNS_DB_TRACE
    178 ISC_REFCOUNT_TRACE_IMPL(dns_db, dns__db_destroy);
    179 #else
    180 ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
    181 #endif
    182 
    183 bool
    184 dns_db_iscache(dns_db_t *db) {
    185 	/*
    186 	 * Does 'db' have cache semantics?
    187 	 */
    188 
    189 	REQUIRE(DNS_DB_VALID(db));
    190 
    191 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
    192 		return true;
    193 	}
    194 
    195 	return false;
    196 }
    197 
    198 bool
    199 dns_db_iszone(dns_db_t *db) {
    200 	/*
    201 	 * Does 'db' have zone semantics?
    202 	 */
    203 
    204 	REQUIRE(DNS_DB_VALID(db));
    205 
    206 	if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) {
    207 		return true;
    208 	}
    209 
    210 	return false;
    211 }
    212 
    213 bool
    214 dns_db_isstub(dns_db_t *db) {
    215 	/*
    216 	 * Does 'db' have stub semantics?
    217 	 */
    218 
    219 	REQUIRE(DNS_DB_VALID(db));
    220 
    221 	if ((db->attributes & DNS_DBATTR_STUB) != 0) {
    222 		return true;
    223 	}
    224 
    225 	return false;
    226 }
    227 
    228 bool
    229 dns_db_issecure(dns_db_t *db) {
    230 	/*
    231 	 * Is 'db' secure?
    232 	 */
    233 
    234 	REQUIRE(DNS_DB_VALID(db));
    235 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    236 
    237 	if (db->methods->issecure != NULL) {
    238 		return (db->methods->issecure)(db);
    239 	}
    240 	return false;
    241 }
    242 
    243 bool
    244 dns_db_ispersistent(dns_db_t *db) {
    245 	/*
    246 	 * Is 'db' persistent?
    247 	 */
    248 
    249 	REQUIRE(DNS_DB_VALID(db));
    250 
    251 	if (db->methods->beginload == NULL) {
    252 		/* If the database can't be loaded, assume it's persistent */
    253 		return true;
    254 	}
    255 
    256 	return false;
    257 }
    258 
    259 dns_name_t *
    260 dns_db_origin(dns_db_t *db) {
    261 	/*
    262 	 * The origin of the database.
    263 	 */
    264 
    265 	REQUIRE(DNS_DB_VALID(db));
    266 
    267 	return &db->origin;
    268 }
    269 
    270 dns_rdataclass_t
    271 dns_db_class(dns_db_t *db) {
    272 	/*
    273 	 * The class of the database.
    274 	 */
    275 
    276 	REQUIRE(DNS_DB_VALID(db));
    277 
    278 	return db->rdclass;
    279 }
    280 
    281 isc_result_t
    282 dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    283 	/*
    284 	 * Begin loading 'db'.
    285 	 */
    286 
    287 	REQUIRE(DNS_DB_VALID(db));
    288 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    289 
    290 	if (db->methods->beginload != NULL) {
    291 		return (db->methods->beginload)(db, callbacks);
    292 	}
    293 	return ISC_R_NOTIMPLEMENTED;
    294 }
    295 
    296 isc_result_t
    297 dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    298 	/*
    299 	 * Finish loading 'db'.
    300 	 */
    301 
    302 	REQUIRE(DNS_DB_VALID(db));
    303 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    304 	REQUIRE(callbacks->add_private != NULL);
    305 
    306 	/*
    307 	 * When dns_db_endload() is called, we call the onupdate function
    308 	 * for all registered listeners, regardless of whether the underlying
    309 	 * database has an 'endload' implementation.
    310 	 */
    311 	call_updatenotify(db);
    312 
    313 	if (db->methods->endload != NULL) {
    314 		return (db->methods->endload)(db, callbacks);
    315 	}
    316 
    317 	return ISC_R_NOTIMPLEMENTED;
    318 }
    319 
    320 isc_result_t
    321 dns_db_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
    322 		   dns_rdatacallbacks_t *callbacks) {
    323 	/*
    324 	 * Begin updating 'db'.
    325 	 */
    326 
    327 	REQUIRE(DNS_DB_VALID(db));
    328 	REQUIRE(dns_db_iszone(db));
    329 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    330 
    331 	if (db->methods->beginupdate != NULL) {
    332 		return (db->methods->beginupdate)(db, ver, callbacks);
    333 	}
    334 	return ISC_R_NOTIMPLEMENTED;
    335 }
    336 
    337 isc_result_t
    338 dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    339 	/*
    340 	 * Commit the update to 'db'.
    341 	 */
    342 
    343 	REQUIRE(DNS_DB_VALID(db));
    344 	REQUIRE(dns_db_iszone(db));
    345 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    346 
    347 	if (db->methods->commitupdate != NULL) {
    348 		return (db->methods->commitupdate)(db, callbacks);
    349 	}
    350 
    351 	return ISC_R_NOTIMPLEMENTED;
    352 }
    353 
    354 isc_result_t
    355 dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    356 	/*
    357 	 * Abort the update to 'db'.
    358 	 */
    359 
    360 	REQUIRE(DNS_DB_VALID(db));
    361 	REQUIRE(dns_db_iszone(db));
    362 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    363 
    364 	if (db->methods->abortupdate != NULL) {
    365 		return (db->methods->abortupdate)(db, callbacks);
    366 	}
    367 
    368 	return ISC_R_NOTIMPLEMENTED;
    369 }
    370 
    371 isc_result_t
    372 dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
    373 	    unsigned int options) {
    374 	isc_result_t result, eresult;
    375 	dns_rdatacallbacks_t callbacks;
    376 
    377 	/*
    378 	 * Load master file 'filename' into 'db'.
    379 	 */
    380 
    381 	REQUIRE(DNS_DB_VALID(db));
    382 
    383 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
    384 		options |= DNS_MASTER_AGETTL;
    385 	}
    386 
    387 	dns_rdatacallbacks_init(&callbacks);
    388 	result = dns_db_beginload(db, &callbacks);
    389 	if (result != ISC_R_SUCCESS) {
    390 		return result;
    391 	}
    392 	result = dns_master_loadfile(filename, &db->origin, &db->origin,
    393 				     db->rdclass, options, 0, &callbacks, NULL,
    394 				     NULL, db->mctx, format, 0);
    395 	eresult = dns_db_endload(db, &callbacks);
    396 	/*
    397 	 * We always call dns_db_endload(), but we only want to return its
    398 	 * result if dns_master_loadfile() succeeded.  If dns_master_loadfile()
    399 	 * failed, we want to return the result code it gave us.
    400 	 */
    401 	if (eresult != ISC_R_SUCCESS &&
    402 	    (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
    403 	{
    404 		result = eresult;
    405 	}
    406 
    407 	return result;
    408 }
    409 
    410 /***
    411  *** Version Methods
    412  ***/
    413 
    414 void
    415 dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
    416 	/*
    417 	 * Open the current version for reading.
    418 	 */
    419 
    420 	REQUIRE(DNS_DB_VALID(db));
    421 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    422 	REQUIRE(versionp != NULL && *versionp == NULL);
    423 
    424 	(db->methods->currentversion)(db, versionp);
    425 }
    426 
    427 isc_result_t
    428 dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
    429 	/*
    430 	 * Open a new version for reading and writing.
    431 	 */
    432 
    433 	REQUIRE(DNS_DB_VALID(db));
    434 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    435 	REQUIRE(versionp != NULL && *versionp == NULL);
    436 
    437 	if (db->methods->newversion != NULL) {
    438 		return (db->methods->newversion)(db, versionp);
    439 	}
    440 	return ISC_R_NOTIMPLEMENTED;
    441 }
    442 
    443 void
    444 dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
    445 		     dns_dbversion_t **targetp) {
    446 	/*
    447 	 * Attach '*targetp' to 'source'.
    448 	 */
    449 
    450 	REQUIRE(DNS_DB_VALID(db));
    451 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    452 	REQUIRE(source != NULL);
    453 	REQUIRE(targetp != NULL && *targetp == NULL);
    454 
    455 	(db->methods->attachversion)(db, source, targetp);
    456 
    457 	ENSURE(*targetp != NULL);
    458 }
    459 
    460 void
    461 dns__db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
    462 		     bool commit DNS__DB_FLARG) {
    463 	/*
    464 	 * Close version '*versionp'.
    465 	 */
    466 
    467 	REQUIRE(DNS_DB_VALID(db));
    468 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    469 	REQUIRE(versionp != NULL && *versionp != NULL);
    470 
    471 	(db->methods->closeversion)(db, versionp, commit DNS__DB_FLARG_PASS);
    472 
    473 	if (commit) {
    474 		call_updatenotify(db);
    475 	}
    476 
    477 	ENSURE(*versionp == NULL);
    478 }
    479 
    480 /***
    481  *** Node Methods
    482  ***/
    483 
    484 isc_result_t
    485 dns__db_findnode(dns_db_t *db, const dns_name_t *name, bool create,
    486 		 dns_dbnode_t **nodep DNS__DB_FLARG) {
    487 	/*
    488 	 * Find the node with name 'name'.
    489 	 */
    490 
    491 	REQUIRE(DNS_DB_VALID(db));
    492 	REQUIRE(nodep != NULL && *nodep == NULL);
    493 
    494 	if (db->methods->findnode != NULL) {
    495 		return (db->methods->findnode)(db, name, create,
    496 					       nodep DNS__DB_FLARG_PASS);
    497 	} else {
    498 		return (db->methods->findnodeext)(db, name, create, NULL, NULL,
    499 						  nodep DNS__DB_FLARG_PASS);
    500 	}
    501 }
    502 
    503 isc_result_t
    504 dns__db_findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
    505 		    dns_clientinfomethods_t *methods,
    506 		    dns_clientinfo_t *clientinfo,
    507 		    dns_dbnode_t **nodep DNS__DB_FLARG) {
    508 	/*
    509 	 * Find the node with name 'name', passing 'arg' to the database
    510 	 * implementation.
    511 	 */
    512 
    513 	REQUIRE(DNS_DB_VALID(db));
    514 	REQUIRE(nodep != NULL && *nodep == NULL);
    515 
    516 	if (db->methods->findnodeext != NULL) {
    517 		return (db->methods->findnodeext)(db, name, create, methods,
    518 						  clientinfo,
    519 						  nodep DNS__DB_FLARG_PASS);
    520 	} else {
    521 		return (db->methods->findnode)(db, name, create,
    522 					       nodep DNS__DB_FLARG_PASS);
    523 	}
    524 }
    525 
    526 isc_result_t
    527 dns__db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
    528 		      dns_dbnode_t **nodep DNS__DB_FLARG) {
    529 	/*
    530 	 * Find the node with name 'name'.
    531 	 */
    532 
    533 	REQUIRE(DNS_DB_VALID(db));
    534 	REQUIRE(nodep != NULL && *nodep == NULL);
    535 
    536 	return (db->methods->findnsec3node)(db, name, create,
    537 					    nodep DNS__DB_FLARG_PASS);
    538 }
    539 
    540 isc_result_t
    541 dns__db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
    542 	     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
    543 	     dns_dbnode_t **nodep, dns_name_t *foundname,
    544 	     dns_rdataset_t *rdataset,
    545 	     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
    546 	/*
    547 	 * Find the best match for 'name' and 'type' in version 'version'
    548 	 * of 'db'.
    549 	 */
    550 
    551 	REQUIRE(DNS_DB_VALID(db));
    552 	REQUIRE(type != dns_rdatatype_rrsig);
    553 	REQUIRE(nodep == NULL || *nodep == NULL);
    554 	REQUIRE(dns_name_hasbuffer(foundname));
    555 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
    556 				     !dns_rdataset_isassociated(rdataset)));
    557 	REQUIRE(sigrdataset == NULL ||
    558 		(DNS_RDATASET_VALID(sigrdataset) &&
    559 		 !dns_rdataset_isassociated(sigrdataset)));
    560 
    561 	if (db->methods->find != NULL) {
    562 		return (db->methods->find)(db, name, version, type, options,
    563 					   now, nodep, foundname, rdataset,
    564 					   sigrdataset DNS__DB_FLARG_PASS);
    565 	} else {
    566 		return (db->methods->findext)(
    567 			db, name, version, type, options, now, nodep, foundname,
    568 			NULL, NULL, rdataset, sigrdataset DNS__DB_FLARG_PASS);
    569 	}
    570 }
    571 
    572 isc_result_t
    573 dns__db_findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
    574 		dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
    575 		dns_dbnode_t **nodep, dns_name_t *foundname,
    576 		dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
    577 		dns_rdataset_t *rdataset,
    578 		dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
    579 	/*
    580 	 * Find the best match for 'name' and 'type' in version 'version'
    581 	 * of 'db', passing in 'arg'.
    582 	 */
    583 
    584 	REQUIRE(DNS_DB_VALID(db));
    585 	REQUIRE(type != dns_rdatatype_rrsig);
    586 	REQUIRE(nodep == NULL || *nodep == NULL);
    587 	REQUIRE(dns_name_hasbuffer(foundname));
    588 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
    589 				     !dns_rdataset_isassociated(rdataset)));
    590 	REQUIRE(sigrdataset == NULL ||
    591 		(DNS_RDATASET_VALID(sigrdataset) &&
    592 		 !dns_rdataset_isassociated(sigrdataset)));
    593 
    594 	if (db->methods->findext != NULL) {
    595 		return (db->methods->findext)(db, name, version, type, options,
    596 					      now, nodep, foundname, methods,
    597 					      clientinfo, rdataset,
    598 					      sigrdataset DNS__DB_FLARG_PASS);
    599 	} else {
    600 		return (db->methods->find)(db, name, version, type, options,
    601 					   now, nodep, foundname, rdataset,
    602 					   sigrdataset DNS__DB_FLARG_PASS);
    603 	}
    604 }
    605 
    606 isc_result_t
    607 dns__db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
    608 		    isc_stdtime_t now, dns_dbnode_t **nodep,
    609 		    dns_name_t *foundname, dns_name_t *dcname,
    610 		    dns_rdataset_t *rdataset,
    611 		    dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
    612 	/*
    613 	 * Find the deepest known zonecut which encloses 'name' in 'db'.
    614 	 * foundname is the zonecut, dcname is the deepest name we have
    615 	 * in database that is part of queried name.
    616 	 */
    617 
    618 	REQUIRE(DNS_DB_VALID(db));
    619 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
    620 	REQUIRE(nodep == NULL || *nodep == NULL);
    621 	REQUIRE(dns_name_hasbuffer(foundname));
    622 	REQUIRE(sigrdataset == NULL ||
    623 		(DNS_RDATASET_VALID(sigrdataset) &&
    624 		 !dns_rdataset_isassociated(sigrdataset)));
    625 
    626 	if (db->methods->findzonecut != NULL) {
    627 		return (db->methods->findzonecut)(
    628 			db, name, options, now, nodep, foundname, dcname,
    629 			rdataset, sigrdataset DNS__DB_FLARG_PASS);
    630 	}
    631 	return ISC_R_NOTIMPLEMENTED;
    632 }
    633 
    634 void
    635 dns__db_attachnode(dns_db_t *db, dns_dbnode_t *source,
    636 		   dns_dbnode_t **targetp DNS__DB_FLARG) {
    637 	/*
    638 	 * Attach *targetp to source.
    639 	 */
    640 
    641 	REQUIRE(DNS_DB_VALID(db));
    642 	REQUIRE(source != NULL);
    643 	REQUIRE(targetp != NULL && *targetp == NULL);
    644 
    645 	(db->methods->attachnode)(db, source, targetp DNS__DB_FLARG_PASS);
    646 }
    647 
    648 void
    649 dns__db_detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
    650 	/*
    651 	 * Detach *nodep from its node.
    652 	 */
    653 
    654 	REQUIRE(DNS_DB_VALID(db));
    655 	REQUIRE(nodep != NULL && *nodep != NULL);
    656 
    657 	(db->methods->detachnode)(db, nodep DNS__DB_FLARG_PASS);
    658 
    659 	ENSURE(*nodep == NULL);
    660 }
    661 
    662 void
    663 dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
    664 		    dns_dbnode_t **targetp) {
    665 	REQUIRE(DNS_DB_VALID(db));
    666 	REQUIRE(targetp != NULL && *targetp == NULL);
    667 	REQUIRE(sourcep != NULL && *sourcep != NULL);
    668 
    669 	*targetp = *sourcep;
    670 	*sourcep = NULL;
    671 }
    672 
    673 /***
    674  *** DB Iterator Creation
    675  ***/
    676 
    677 isc_result_t
    678 dns_db_createiterator(dns_db_t *db, unsigned int flags,
    679 		      dns_dbiterator_t **iteratorp) {
    680 	/*
    681 	 * Create an iterator for version 'version' of 'db'.
    682 	 */
    683 
    684 	REQUIRE(DNS_DB_VALID(db));
    685 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
    686 	REQUIRE((flags & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) !=
    687 		(DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3));
    688 
    689 	if (db->methods->createiterator != NULL) {
    690 		return db->methods->createiterator(db, flags, iteratorp);
    691 	}
    692 	return ISC_R_NOTIMPLEMENTED;
    693 }
    694 
    695 /***
    696  *** Rdataset Methods
    697  ***/
    698 
    699 isc_result_t
    700 dns__db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    701 		     dns_rdatatype_t type, dns_rdatatype_t covers,
    702 		     isc_stdtime_t now, dns_rdataset_t *rdataset,
    703 		     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
    704 	REQUIRE(DNS_DB_VALID(db));
    705 	REQUIRE(node != NULL);
    706 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    707 	REQUIRE(!dns_rdataset_isassociated(rdataset));
    708 	REQUIRE(covers == dns_rdatatype_none || type == dns_rdatatype_rrsig ||
    709 		type == dns_rdatatype_sig);
    710 	REQUIRE(type != dns_rdatatype_any);
    711 	REQUIRE(sigrdataset == NULL ||
    712 		(DNS_RDATASET_VALID(sigrdataset) &&
    713 		 !dns_rdataset_isassociated(sigrdataset)));
    714 
    715 	return (db->methods->findrdataset)(db, node, version, type, covers, now,
    716 					   rdataset,
    717 					   sigrdataset DNS__DB_FLARG_PASS);
    718 }
    719 
    720 isc_result_t
    721 dns__db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    722 		     unsigned int options, isc_stdtime_t now,
    723 		     dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
    724 	/*
    725 	 * Make '*iteratorp' an rdataset iteratator for all rdatasets at
    726 	 * 'node' in version 'version' of 'db'.
    727 	 */
    728 
    729 	REQUIRE(DNS_DB_VALID(db));
    730 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
    731 
    732 	return (db->methods->allrdatasets)(db, node, version, options, now,
    733 					   iteratorp DNS__DB_FLARG_PASS);
    734 }
    735 
    736 isc_result_t
    737 dns__db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    738 		    isc_stdtime_t now, dns_rdataset_t *rdataset,
    739 		    unsigned int options,
    740 		    dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
    741 	/*
    742 	 * Add 'rdataset' to 'node' in version 'version' of 'db'.
    743 	 */
    744 
    745 	REQUIRE(DNS_DB_VALID(db));
    746 	REQUIRE(node != NULL);
    747 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
    748 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
    749 		 (options & DNS_DBADD_MERGE) == 0));
    750 	REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
    751 		(options & DNS_DBADD_MERGE) != 0);
    752 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    753 	REQUIRE(dns_rdataset_isassociated(rdataset));
    754 	REQUIRE(rdataset->rdclass == db->rdclass);
    755 	REQUIRE(addedrdataset == NULL ||
    756 		(DNS_RDATASET_VALID(addedrdataset) &&
    757 		 !dns_rdataset_isassociated(addedrdataset)));
    758 
    759 	if (db->methods->addrdataset != NULL) {
    760 		return (db->methods->addrdataset)(
    761 			db, node, version, now, rdataset, options,
    762 			addedrdataset DNS__DB_FLARG_PASS);
    763 	}
    764 	return ISC_R_NOTIMPLEMENTED;
    765 }
    766 
    767 isc_result_t
    768 dns__db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
    769 			 dns_dbversion_t *version, dns_rdataset_t *rdataset,
    770 			 unsigned int options,
    771 			 dns_rdataset_t *newrdataset DNS__DB_FLARG) {
    772 	/*
    773 	 * Remove any rdata in 'rdataset' from 'node' in version 'version' of
    774 	 * 'db'.
    775 	 */
    776 
    777 	REQUIRE(DNS_DB_VALID(db));
    778 	REQUIRE(node != NULL);
    779 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
    780 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    781 	REQUIRE(dns_rdataset_isassociated(rdataset));
    782 	REQUIRE(rdataset->rdclass == db->rdclass);
    783 	REQUIRE(newrdataset == NULL ||
    784 		(DNS_RDATASET_VALID(newrdataset) &&
    785 		 !dns_rdataset_isassociated(newrdataset)));
    786 
    787 	if (db->methods->subtractrdataset != NULL) {
    788 		return (db->methods->subtractrdataset)(
    789 			db, node, version, rdataset, options,
    790 			newrdataset DNS__DB_FLARG_PASS);
    791 	}
    792 	return ISC_R_NOTIMPLEMENTED;
    793 }
    794 
    795 isc_result_t
    796 dns__db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
    797 		       dns_dbversion_t *version, dns_rdatatype_t type,
    798 		       dns_rdatatype_t covers DNS__DB_FLARG) {
    799 	/*
    800 	 * Make it so that no rdataset of type 'type' exists at 'node' in
    801 	 * version version 'version' of 'db'.
    802 	 */
    803 
    804 	REQUIRE(DNS_DB_VALID(db));
    805 	REQUIRE(node != NULL);
    806 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
    807 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
    808 
    809 	if (db->methods->deleterdataset != NULL) {
    810 		return (db->methods->deleterdataset)(db, node, version, type,
    811 						     covers DNS__DB_FLARG_PASS);
    812 	}
    813 	return ISC_R_NOTIMPLEMENTED;
    814 }
    815 
    816 isc_result_t
    817 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
    818 	isc_result_t result;
    819 	dns_dbnode_t *node = NULL;
    820 	dns_rdataset_t rdataset;
    821 	dns_rdata_t rdata = DNS_RDATA_INIT;
    822 	isc_buffer_t buffer;
    823 
    824 	REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
    825 
    826 	result = dns_db_findnode(db, dns_db_origin(db), false, &node);
    827 	if (result != ISC_R_SUCCESS) {
    828 		return result;
    829 	}
    830 
    831 	dns_rdataset_init(&rdataset);
    832 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
    833 				     (isc_stdtime_t)0, &rdataset, NULL);
    834 	if (result != ISC_R_SUCCESS) {
    835 		goto freenode;
    836 	}
    837 
    838 	result = dns_rdataset_first(&rdataset);
    839 	if (result != ISC_R_SUCCESS) {
    840 		goto freerdataset;
    841 	}
    842 	dns_rdataset_current(&rdataset, &rdata);
    843 	result = dns_rdataset_next(&rdataset);
    844 	INSIST(result == ISC_R_NOMORE);
    845 
    846 	INSIST(rdata.length > 20);
    847 	isc_buffer_init(&buffer, rdata.data, rdata.length);
    848 	isc_buffer_add(&buffer, rdata.length);
    849 	isc_buffer_forward(&buffer, rdata.length - 20);
    850 	*serialp = isc_buffer_getuint32(&buffer);
    851 
    852 	result = ISC_R_SUCCESS;
    853 
    854 freerdataset:
    855 	dns_rdataset_disassociate(&rdataset);
    856 
    857 freenode:
    858 	dns_db_detachnode(db, &node);
    859 	return result;
    860 }
    861 
    862 unsigned int
    863 dns_db_nodecount(dns_db_t *db, dns_dbtree_t tree) {
    864 	REQUIRE(DNS_DB_VALID(db));
    865 
    866 	if (db->methods->nodecount != NULL) {
    867 		return (db->methods->nodecount)(db, tree);
    868 	}
    869 	return 0;
    870 }
    871 
    872 size_t
    873 dns_db_hashsize(dns_db_t *db) {
    874 	REQUIRE(DNS_DB_VALID(db));
    875 
    876 	if (db->methods->hashsize == NULL) {
    877 		return 0;
    878 	}
    879 
    880 	return (db->methods->hashsize)(db);
    881 }
    882 
    883 void
    884 dns_db_setloop(dns_db_t *db, isc_loop_t *loop) {
    885 	REQUIRE(DNS_DB_VALID(db));
    886 
    887 	if (db->methods->setloop != NULL) {
    888 		(db->methods->setloop)(db, loop);
    889 	}
    890 }
    891 
    892 isc_result_t
    893 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
    894 		isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
    895 	dns_dbimplementation_t *imp;
    896 
    897 	REQUIRE(name != NULL);
    898 	REQUIRE(dbimp != NULL && *dbimp == NULL);
    899 
    900 	isc_once_do(&once, initialize);
    901 
    902 	RWLOCK(&implock, isc_rwlocktype_write);
    903 	imp = impfind(name);
    904 	if (imp != NULL) {
    905 		RWUNLOCK(&implock, isc_rwlocktype_write);
    906 		return ISC_R_EXISTS;
    907 	}
    908 
    909 	imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
    910 	imp->name = name;
    911 	imp->create = create;
    912 	imp->mctx = NULL;
    913 	imp->driverarg = driverarg;
    914 	isc_mem_attach(mctx, &imp->mctx);
    915 	ISC_LINK_INIT(imp, link);
    916 	ISC_LIST_APPEND(implementations, imp, link);
    917 	RWUNLOCK(&implock, isc_rwlocktype_write);
    918 
    919 	*dbimp = imp;
    920 
    921 	return ISC_R_SUCCESS;
    922 }
    923 
    924 void
    925 dns_db_unregister(dns_dbimplementation_t **dbimp) {
    926 	dns_dbimplementation_t *imp;
    927 
    928 	REQUIRE(dbimp != NULL && *dbimp != NULL);
    929 
    930 	isc_once_do(&once, initialize);
    931 
    932 	imp = *dbimp;
    933 	*dbimp = NULL;
    934 	RWLOCK(&implock, isc_rwlocktype_write);
    935 	ISC_LIST_UNLINK(implementations, imp, link);
    936 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
    937 	RWUNLOCK(&implock, isc_rwlocktype_write);
    938 	ENSURE(*dbimp == NULL);
    939 }
    940 
    941 isc_result_t
    942 dns__db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
    943 	REQUIRE(DNS_DB_VALID(db));
    944 	REQUIRE(dns_db_iszone(db));
    945 	REQUIRE(nodep != NULL && *nodep == NULL);
    946 
    947 	if (db->methods->getoriginnode != NULL) {
    948 		return (db->methods->getoriginnode)(db,
    949 						    nodep DNS__DB_FLARG_PASS);
    950 	}
    951 
    952 	return ISC_R_NOTFOUND;
    953 }
    954 
    955 dns_stats_t *
    956 dns_db_getrrsetstats(dns_db_t *db) {
    957 	REQUIRE(DNS_DB_VALID(db));
    958 
    959 	if (db->methods->getrrsetstats != NULL) {
    960 		return (db->methods->getrrsetstats)(db);
    961 	}
    962 
    963 	return NULL;
    964 }
    965 
    966 isc_result_t
    967 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
    968 	REQUIRE(DNS_DB_VALID(db));
    969 
    970 	if (db->methods->setcachestats != NULL) {
    971 		return (db->methods->setcachestats)(db, stats);
    972 	}
    973 
    974 	return ISC_R_NOTIMPLEMENTED;
    975 }
    976 
    977 isc_result_t
    978 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
    979 			  dns_hash_t *hash, uint8_t *flags,
    980 			  uint16_t *iterations, unsigned char *salt,
    981 			  size_t *salt_length) {
    982 	REQUIRE(DNS_DB_VALID(db));
    983 	REQUIRE(dns_db_iszone(db));
    984 
    985 	if (db->methods->getnsec3parameters != NULL) {
    986 		return (db->methods->getnsec3parameters)(db, version, hash,
    987 							 flags, iterations,
    988 							 salt, salt_length);
    989 	}
    990 
    991 	return ISC_R_NOTFOUND;
    992 }
    993 
    994 isc_result_t
    995 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
    996 	       uint64_t *bytes) {
    997 	REQUIRE(DNS_DB_VALID(db));
    998 	REQUIRE(dns_db_iszone(db));
    999 
   1000 	if (db->methods->getsize != NULL) {
   1001 		return (db->methods->getsize)(db, version, records, bytes);
   1002 	}
   1003 
   1004 	return ISC_R_NOTFOUND;
   1005 }
   1006 
   1007 isc_result_t
   1008 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
   1009 		      isc_stdtime_t resign) {
   1010 	if (db->methods->setsigningtime != NULL) {
   1011 		return (db->methods->setsigningtime)(db, rdataset, resign);
   1012 	}
   1013 	return ISC_R_NOTIMPLEMENTED;
   1014 }
   1015 
   1016 isc_result_t
   1017 dns_db_getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *name,
   1018 		      dns_typepair_t *typepair) {
   1019 	if (db->methods->getsigningtime != NULL) {
   1020 		return (db->methods->getsigningtime)(db, resign, name,
   1021 						     typepair);
   1022 	}
   1023 	return ISC_R_NOTFOUND;
   1024 }
   1025 
   1026 static void
   1027 call_updatenotify(dns_db_t *db) {
   1028 	rcu_read_lock();
   1029 	struct cds_lfht *update_listeners =
   1030 		rcu_dereference(db->update_listeners);
   1031 	if (update_listeners != NULL) {
   1032 		struct cds_lfht_iter iter;
   1033 		dns_dbonupdatelistener_t *listener;
   1034 		cds_lfht_for_each_entry(update_listeners, &iter, listener,
   1035 					ht_node) {
   1036 			if (!cds_lfht_is_node_deleted(&listener->ht_node)) {
   1037 				listener->onupdate(db, listener->onupdate_arg);
   1038 			}
   1039 		}
   1040 	}
   1041 	rcu_read_unlock();
   1042 }
   1043 
   1044 static void
   1045 updatenotify_free(struct rcu_head *rcu_head) {
   1046 	dns_dbonupdatelistener_t *listener =
   1047 		caa_container_of(rcu_head, dns_dbonupdatelistener_t, rcu_head);
   1048 	isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
   1049 }
   1050 
   1051 static int
   1052 updatenotify_match(struct cds_lfht_node *ht_node, const void *_key) {
   1053 	const dns_dbonupdatelistener_t *listener =
   1054 		caa_container_of(ht_node, dns_dbonupdatelistener_t, ht_node);
   1055 	const dns_dbonupdatelistener_t *key = _key;
   1056 
   1057 	return listener->onupdate == key->onupdate &&
   1058 	       listener->onupdate_arg == key->onupdate_arg;
   1059 }
   1060 
   1061 /*
   1062  * Attach a notify-on-update function the database
   1063  */
   1064 void
   1065 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
   1066 			     void *fn_arg) {
   1067 	REQUIRE(db != NULL);
   1068 	REQUIRE(fn != NULL);
   1069 
   1070 	dns_dbonupdatelistener_t key = { .onupdate = fn,
   1071 					 .onupdate_arg = fn_arg };
   1072 	uint32_t hash = isc_hash32(&key, sizeof(key), true);
   1073 	dns_dbonupdatelistener_t *listener = isc_mem_get(db->mctx,
   1074 							 sizeof(*listener));
   1075 	*listener = key;
   1076 
   1077 	isc_mem_attach(db->mctx, &listener->mctx);
   1078 
   1079 	rcu_read_lock();
   1080 	struct cds_lfht *update_listeners =
   1081 		rcu_dereference(db->update_listeners);
   1082 	INSIST(update_listeners != NULL);
   1083 	struct cds_lfht_node *ht_node =
   1084 		cds_lfht_add_unique(update_listeners, hash, updatenotify_match,
   1085 				    &key, &listener->ht_node);
   1086 	rcu_read_unlock();
   1087 
   1088 	if (ht_node != &listener->ht_node) {
   1089 		updatenotify_free(&listener->rcu_head);
   1090 	}
   1091 }
   1092 
   1093 void
   1094 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
   1095 			       void *fn_arg) {
   1096 	REQUIRE(db != NULL);
   1097 
   1098 	dns_dbonupdatelistener_t key = { .onupdate = fn,
   1099 					 .onupdate_arg = fn_arg };
   1100 	uint32_t hash = isc_hash32(&key, sizeof(key), true);
   1101 	struct cds_lfht_iter iter;
   1102 
   1103 	rcu_read_lock();
   1104 	struct cds_lfht *update_listeners =
   1105 		rcu_dereference(db->update_listeners);
   1106 	INSIST(update_listeners != NULL);
   1107 	cds_lfht_lookup(update_listeners, hash, updatenotify_match, &key,
   1108 			&iter);
   1109 
   1110 	struct cds_lfht_node *ht_node = cds_lfht_iter_get_node(&iter);
   1111 	if (ht_node != NULL && !cds_lfht_del(update_listeners, ht_node)) {
   1112 		dns_dbonupdatelistener_t *listener = caa_container_of(
   1113 			ht_node, dns_dbonupdatelistener_t, ht_node);
   1114 		call_rcu(&listener->rcu_head, updatenotify_free);
   1115 	}
   1116 	rcu_read_unlock();
   1117 }
   1118 
   1119 isc_result_t
   1120 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
   1121 	REQUIRE(DNS_DB_VALID(db));
   1122 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1123 
   1124 	if (db->methods->setservestalettl != NULL) {
   1125 		return (db->methods->setservestalettl)(db, ttl);
   1126 	}
   1127 	return ISC_R_NOTIMPLEMENTED;
   1128 }
   1129 
   1130 isc_result_t
   1131 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
   1132 	REQUIRE(DNS_DB_VALID(db));
   1133 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1134 
   1135 	if (db->methods->getservestalettl != NULL) {
   1136 		return (db->methods->getservestalettl)(db, ttl);
   1137 	}
   1138 	return ISC_R_NOTIMPLEMENTED;
   1139 }
   1140 
   1141 isc_result_t
   1142 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
   1143 	REQUIRE(DNS_DB_VALID(db));
   1144 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1145 
   1146 	if (db->methods->setservestalerefresh != NULL) {
   1147 		return (db->methods->setservestalerefresh)(db, interval);
   1148 	}
   1149 	return ISC_R_NOTIMPLEMENTED;
   1150 }
   1151 
   1152 isc_result_t
   1153 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
   1154 	REQUIRE(DNS_DB_VALID(db));
   1155 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1156 
   1157 	if (db->methods->getservestalerefresh != NULL) {
   1158 		return (db->methods->getservestalerefresh)(db, interval);
   1159 	}
   1160 	return ISC_R_NOTIMPLEMENTED;
   1161 }
   1162 
   1163 isc_result_t
   1164 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
   1165 	REQUIRE(dns_db_iszone(db));
   1166 	REQUIRE(stats != NULL);
   1167 
   1168 	if (db->methods->setgluecachestats != NULL) {
   1169 		return (db->methods->setgluecachestats)(db, stats);
   1170 	}
   1171 
   1172 	return ISC_R_NOTIMPLEMENTED;
   1173 }
   1174 
   1175 isc_result_t
   1176 dns_db_addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
   1177 	       dns_message_t *msg) {
   1178 	REQUIRE(DNS_DB_VALID(db));
   1179 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
   1180 	REQUIRE(DNS_RDATASET_VALID(rdataset));
   1181 	REQUIRE(rdataset->methods != NULL);
   1182 	REQUIRE(rdataset->type == dns_rdatatype_ns);
   1183 
   1184 	if (db->methods->addglue != NULL) {
   1185 		(db->methods->addglue)(db, version, rdataset, msg);
   1186 
   1187 		return ISC_R_SUCCESS;
   1188 	}
   1189 
   1190 	return ISC_R_NOTIMPLEMENTED;
   1191 }
   1192 
   1193 void
   1194 dns_db_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
   1195 	if (db->methods->locknode != NULL) {
   1196 		(db->methods->locknode)(db, node, type);
   1197 	}
   1198 }
   1199 
   1200 void
   1201 dns_db_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
   1202 	if (db->methods->unlocknode != NULL) {
   1203 		(db->methods->unlocknode)(db, node, type);
   1204 	}
   1205 }
   1206 
   1207 void
   1208 dns_db_expiredata(dns_db_t *db, dns_dbnode_t *node, void *data) {
   1209 	if (db->methods->expiredata != NULL) {
   1210 		(db->methods->expiredata)(db, node, data);
   1211 	}
   1212 }
   1213 
   1214 void
   1215 dns_db_deletedata(dns_db_t *db, dns_dbnode_t *node, void *data) {
   1216 	if (db->methods->deletedata != NULL) {
   1217 		(db->methods->deletedata)(db, node, data);
   1218 	}
   1219 }
   1220 
   1221 isc_result_t
   1222 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
   1223 	REQUIRE(db != NULL);
   1224 	REQUIRE(node != NULL);
   1225 	REQUIRE(name != NULL);
   1226 
   1227 	if (db->methods->nodefullname != NULL) {
   1228 		return (db->methods->nodefullname)(db, node, name);
   1229 	}
   1230 	return ISC_R_NOTIMPLEMENTED;
   1231 }
   1232 
   1233 void
   1234 dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
   1235 	REQUIRE(DNS_DB_VALID(db));
   1236 
   1237 	if (db->methods->setmaxrrperset != NULL) {
   1238 		(db->methods->setmaxrrperset)(db, value);
   1239 	}
   1240 }
   1241 
   1242 void
   1243 dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
   1244 	REQUIRE(DNS_DB_VALID(db));
   1245 
   1246 	if (db->methods->setmaxtypepername != NULL) {
   1247 		(db->methods->setmaxtypepername)(db, value);
   1248 	}
   1249 }
   1250 
   1251 void
   1252 dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
   1253 			  dns_rdatatype_t type, const char *op,
   1254 			  uint32_t limit) {
   1255 	char namebuf[DNS_NAME_FORMATSIZE];
   1256 	char originbuf[DNS_NAME_FORMATSIZE];
   1257 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   1258 	char clsbuf[DNS_RDATACLASS_FORMATSIZE];
   1259 
   1260 	dns_name_format(name, namebuf, sizeof(namebuf));
   1261 	dns_name_format(&db->origin, originbuf, sizeof(originbuf));
   1262 	dns_rdatatype_format(type, typebuf, sizeof(typebuf));
   1263 	dns_rdataclass_format(db->rdclass, clsbuf, sizeof(clsbuf));
   1264 
   1265 	isc_log_write(
   1266 		dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
   1267 		ISC_LOG_ERROR,
   1268 		"error %s '%s/%s' in '%s/%s' (%s): %s (must not exceed %u)", op,
   1269 		namebuf, typebuf, originbuf, clsbuf,
   1270 		(db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
   1271 		isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
   1272 }
   1273 
   1274 void
   1275 dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue) {
   1276 	while (glue != NULL) {
   1277 		dns_glue_t *next = glue->next;
   1278 
   1279 		if (dns_rdataset_isassociated(&glue->rdataset_a)) {
   1280 			dns_rdataset_disassociate(&glue->rdataset_a);
   1281 		}
   1282 		if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
   1283 			dns_rdataset_disassociate(&glue->sigrdataset_a);
   1284 		}
   1285 
   1286 		if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
   1287 			dns_rdataset_disassociate(&glue->rdataset_aaaa);
   1288 		}
   1289 		if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
   1290 			dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
   1291 		}
   1292 
   1293 		dns_rdataset_invalidate(&glue->rdataset_a);
   1294 		dns_rdataset_invalidate(&glue->sigrdataset_a);
   1295 		dns_rdataset_invalidate(&glue->rdataset_aaaa);
   1296 		dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
   1297 
   1298 		dns_name_free(&glue->name, mctx);
   1299 
   1300 		isc_mem_put(mctx, glue, sizeof(*glue));
   1301 
   1302 		glue = next;
   1303 	}
   1304 }
   1305 
   1306 void
   1307 dns__db_destroy_gluelist(dns_gluelist_t **gluelistp) {
   1308 	REQUIRE(gluelistp != NULL);
   1309 	if (*gluelistp == NULL) {
   1310 		return;
   1311 	}
   1312 
   1313 	dns_gluelist_t *gluelist = *gluelistp;
   1314 
   1315 	dns__db_free_glue(gluelist->mctx, gluelist->glue);
   1316 
   1317 	isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist));
   1318 }
   1319 
   1320 void
   1321 dns__db_free_gluelist_rcu(struct rcu_head *rcu_head) {
   1322 	dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t,
   1323 						    rcu_head);
   1324 	dns__db_destroy_gluelist(&gluelist);
   1325 }
   1326 
   1327 void
   1328 dns__db_cleanup_gluelists(struct cds_wfs_stack *glue_stack) {
   1329 	struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
   1330 	struct cds_wfs_node *node = NULL, *next = NULL;
   1331 
   1332 	rcu_read_lock();
   1333 	cds_wfs_for_each_blocking_safe(head, node, next) {
   1334 		dns_gluelist_t *gluelist =
   1335 			caa_container_of(node, dns_gluelist_t, wfs_node);
   1336 		dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header,
   1337 							    NULL);
   1338 		(void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL);
   1339 
   1340 		call_rcu(&gluelist->rcu_head, dns__db_free_gluelist_rcu);
   1341 	}
   1342 	rcu_read_unlock();
   1343 }
   1344 
   1345 #define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
   1346 
   1347 static void
   1348 addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
   1349 	for (; ge != NULL; ge = ge->next) {
   1350 		dns_name_t *name = NULL;
   1351 		dns_rdataset_t *rdataset_a = NULL;
   1352 		dns_rdataset_t *sigrdataset_a = NULL;
   1353 		dns_rdataset_t *rdataset_aaaa = NULL;
   1354 		dns_rdataset_t *sigrdataset_aaaa = NULL;
   1355 		bool prepend_name = false;
   1356 
   1357 		dns_message_gettempname(msg, &name);
   1358 
   1359 		dns_name_copy(&ge->name, name);
   1360 
   1361 		if (dns_rdataset_isassociated(&ge->rdataset_a)) {
   1362 			dns_message_gettemprdataset(msg, &rdataset_a);
   1363 		}
   1364 
   1365 		if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
   1366 			dns_message_gettemprdataset(msg, &sigrdataset_a);
   1367 		}
   1368 
   1369 		if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
   1370 			dns_message_gettemprdataset(msg, &rdataset_aaaa);
   1371 		}
   1372 
   1373 		if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
   1374 			dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
   1375 		}
   1376 
   1377 		if (rdataset_a != NULL) {
   1378 			dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
   1379 			ISC_LIST_APPEND(name->list, rdataset_a, link);
   1380 			if (IS_REQUIRED_GLUE(rdataset_a)) {
   1381 				prepend_name = true;
   1382 			}
   1383 		}
   1384 
   1385 		if (sigrdataset_a != NULL) {
   1386 			dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
   1387 			ISC_LIST_APPEND(name->list, sigrdataset_a, link);
   1388 		}
   1389 
   1390 		if (rdataset_aaaa != NULL) {
   1391 			dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
   1392 			ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
   1393 			if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
   1394 				prepend_name = true;
   1395 			}
   1396 		}
   1397 		if (sigrdataset_aaaa != NULL) {
   1398 			dns_rdataset_clone(&ge->sigrdataset_aaaa,
   1399 					   sigrdataset_aaaa);
   1400 			ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
   1401 		}
   1402 
   1403 		dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
   1404 
   1405 		/*
   1406 		 * When looking for required glue, dns_message_rendersection()
   1407 		 * only processes the first rdataset associated with the first
   1408 		 * name added to the ADDITIONAL section.  dns_message_addname()
   1409 		 * performs an append on the list of names in a given section,
   1410 		 * so if any glue record was marked as required, we need to
   1411 		 * move the name it is associated with to the beginning of the
   1412 		 * list for the ADDITIONAL section or else required glue might
   1413 		 * not be rendered.
   1414 		 */
   1415 		if (prepend_name) {
   1416 			ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
   1417 					name, link);
   1418 			ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
   1419 					 name, link);
   1420 		}
   1421 	}
   1422 }
   1423 
   1424 static dns_gluelist_t *
   1425 new_gluelist(dns_db_t *db, dns_slabheader_t *header,
   1426 	     const dns_dbversion_t *dbversion) {
   1427 	dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist));
   1428 	*gluelist = (dns_gluelist_t){
   1429 		.version = dbversion,
   1430 		.header = header,
   1431 	};
   1432 
   1433 	isc_mem_attach(db->mctx, &gluelist->mctx);
   1434 
   1435 	cds_wfs_node_init(&gluelist->wfs_node);
   1436 
   1437 	return gluelist;
   1438 }
   1439 
   1440 static dns_gluelist_t *
   1441 create_gluelist(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *dbnode,
   1442 		dns_rdataset_t *rdataset, dns_additionaldatafunc_t add) {
   1443 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
   1444 	dns_glue_additionaldata_ctx_t ctx = {
   1445 		.db = db,
   1446 		.version = dbversion,
   1447 		.node = dbnode,
   1448 	};
   1449 	dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version);
   1450 
   1451 	/*
   1452 	 * Get the owner name of the NS RRset - it will be necessary for
   1453 	 * identifying required glue in glue_nsdname_cb() (by
   1454 	 * determining which NS records in the delegation are
   1455 	 * in-bailiwick).
   1456 	 */
   1457 
   1458 	(void)dns_rdataset_additionaldata(rdataset, dns_rootname, add, &ctx, 0);
   1459 
   1460 	CMM_STORE_SHARED(gluelist->glue, ctx.glue);
   1461 
   1462 	return gluelist;
   1463 }
   1464 
   1465 isc_result_t
   1466 dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion,
   1467 		dns_rdataset_t *rdataset, dns_message_t *msg,
   1468 		dns_additionaldatafunc_t add,
   1469 		struct cds_wfs_stack *glue_stack) {
   1470 	dns_dbnode_t *dbnode = (dns_dbnode_t *)rdataset->slab.node;
   1471 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
   1472 	dns_glue_t *glue = NULL;
   1473 	isc_result_t result = ISC_R_SUCCESS;
   1474 
   1475 	REQUIRE(rdataset->type == dns_rdatatype_ns);
   1476 
   1477 	rcu_read_lock();
   1478 
   1479 	dns_gluelist_t *gluelist = rcu_dereference(header->gluelist);
   1480 	if (gluelist == NULL || gluelist->version != dbversion) {
   1481 		/* No or old glue list was found in the table. */
   1482 
   1483 		dns_gluelist_t *xchg_gluelist = gluelist;
   1484 		dns_gluelist_t *old_gluelist = (void *)-1;
   1485 		dns_gluelist_t *new_gluelist =
   1486 			create_gluelist(db, dbversion, dbnode, rdataset, add);
   1487 
   1488 		while (old_gluelist != xchg_gluelist &&
   1489 		       (xchg_gluelist == NULL ||
   1490 			xchg_gluelist->version != dbversion))
   1491 		{
   1492 			old_gluelist = xchg_gluelist;
   1493 			xchg_gluelist = rcu_cmpxchg_pointer(
   1494 				&header->gluelist, old_gluelist, new_gluelist);
   1495 		}
   1496 
   1497 		if (old_gluelist == xchg_gluelist) {
   1498 			/* CAS was successful */
   1499 			cds_wfs_push(glue_stack, &new_gluelist->wfs_node);
   1500 			gluelist = new_gluelist;
   1501 		} else {
   1502 			dns__db_destroy_gluelist(&new_gluelist);
   1503 			gluelist = xchg_gluelist;
   1504 		}
   1505 	}
   1506 
   1507 	glue = CMM_LOAD_SHARED(gluelist->glue);
   1508 
   1509 	if (glue != NULL) {
   1510 		addglue_to_message(glue, msg);
   1511 		result = ISC_R_NOTFOUND;
   1512 	}
   1513 
   1514 	rcu_read_unlock();
   1515 
   1516 	return result;
   1517 }
   1518 
   1519 dns_glue_t *
   1520 dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name) {
   1521 	dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
   1522 	*glue = (dns_glue_t){
   1523 		.name = DNS_NAME_INITEMPTY,
   1524 	};
   1525 
   1526 	dns_name_dup(name, mctx, &glue->name);
   1527 
   1528 	return glue;
   1529 }
   1530