Home | History | Annotate | Line # | Download | only in dns
db.c revision 1.1.2.2
      1 /*	$NetBSD: db.c,v 1.1.2.2 2024/02/24 13:06:56 martin 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/mem.h>
     27 #include <isc/once.h>
     28 #include <isc/rwlock.h>
     29 #include <isc/string.h>
     30 #include <isc/util.h>
     31 
     32 #include <dns/callbacks.h>
     33 #include <dns/clientinfo.h>
     34 #include <dns/db.h>
     35 #include <dns/dbiterator.h>
     36 #include <dns/log.h>
     37 #include <dns/master.h>
     38 #include <dns/rdata.h>
     39 #include <dns/rdataset.h>
     40 #include <dns/rdatasetiter.h>
     41 #include <dns/result.h>
     42 
     43 /***
     44  *** Private Types
     45  ***/
     46 
     47 struct dns_dbimplementation {
     48 	const char *name;
     49 	dns_dbcreatefunc_t create;
     50 	isc_mem_t *mctx;
     51 	void *driverarg;
     52 	ISC_LINK(dns_dbimplementation_t) link;
     53 };
     54 
     55 /***
     56  *** Supported DB Implementations Registry
     57  ***/
     58 
     59 /*
     60  * Built in database implementations are registered here.
     61  */
     62 
     63 #include "rbtdb.h"
     64 
     65 static ISC_LIST(dns_dbimplementation_t) implementations;
     66 static isc_rwlock_t implock;
     67 static isc_once_t once = ISC_ONCE_INIT;
     68 
     69 static dns_dbimplementation_t rbtimp;
     70 
     71 static void
     72 initialize(void) {
     73 	isc_rwlock_init(&implock, 0, 0);
     74 
     75 	rbtimp.name = "rbt";
     76 	rbtimp.create = dns_rbtdb_create;
     77 	rbtimp.mctx = NULL;
     78 	rbtimp.driverarg = NULL;
     79 	ISC_LINK_INIT(&rbtimp, link);
     80 
     81 	ISC_LIST_INIT(implementations);
     82 	ISC_LIST_APPEND(implementations, &rbtimp, link);
     83 }
     84 
     85 static dns_dbimplementation_t *
     86 impfind(const char *name) {
     87 	dns_dbimplementation_t *imp;
     88 
     89 	for (imp = ISC_LIST_HEAD(implementations); imp != NULL;
     90 	     imp = ISC_LIST_NEXT(imp, link))
     91 	{
     92 		if (strcasecmp(name, imp->name) == 0) {
     93 			return (imp);
     94 		}
     95 	}
     96 	return (NULL);
     97 }
     98 
     99 /***
    100  *** Basic DB Methods
    101  ***/
    102 
    103 isc_result_t
    104 dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin,
    105 	      dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc,
    106 	      char *argv[], dns_db_t **dbp) {
    107 	dns_dbimplementation_t *impinfo;
    108 
    109 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
    110 
    111 	/*
    112 	 * Create a new database using implementation 'db_type'.
    113 	 */
    114 
    115 	REQUIRE(dbp != NULL && *dbp == NULL);
    116 	REQUIRE(dns_name_isabsolute(origin));
    117 
    118 	RWLOCK(&implock, isc_rwlocktype_read);
    119 	impinfo = impfind(db_type);
    120 	if (impinfo != NULL) {
    121 		isc_result_t result;
    122 		result = ((impinfo->create)(mctx, origin, type, rdclass, argc,
    123 					    argv, impinfo->driverarg, dbp));
    124 		RWUNLOCK(&implock, isc_rwlocktype_read);
    125 		return (result);
    126 	}
    127 
    128 	RWUNLOCK(&implock, isc_rwlocktype_read);
    129 
    130 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
    131 		      ISC_LOG_ERROR, "unsupported database type '%s'", db_type);
    132 
    133 	return (ISC_R_NOTFOUND);
    134 }
    135 
    136 void
    137 dns_db_attach(dns_db_t *source, dns_db_t **targetp) {
    138 	/*
    139 	 * Attach *targetp to source.
    140 	 */
    141 
    142 	REQUIRE(DNS_DB_VALID(source));
    143 	REQUIRE(targetp != NULL && *targetp == NULL);
    144 
    145 	(source->methods->attach)(source, targetp);
    146 
    147 	ENSURE(*targetp == source);
    148 }
    149 
    150 void
    151 dns_db_detach(dns_db_t **dbp) {
    152 	/*
    153 	 * Detach *dbp from its database.
    154 	 */
    155 
    156 	REQUIRE(dbp != NULL);
    157 	REQUIRE(DNS_DB_VALID(*dbp));
    158 
    159 	((*dbp)->methods->detach)(dbp);
    160 
    161 	ENSURE(*dbp == NULL);
    162 }
    163 
    164 bool
    165 dns_db_iscache(dns_db_t *db) {
    166 	/*
    167 	 * Does 'db' have cache semantics?
    168 	 */
    169 
    170 	REQUIRE(DNS_DB_VALID(db));
    171 
    172 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
    173 		return (true);
    174 	}
    175 
    176 	return (false);
    177 }
    178 
    179 bool
    180 dns_db_iszone(dns_db_t *db) {
    181 	/*
    182 	 * Does 'db' have zone semantics?
    183 	 */
    184 
    185 	REQUIRE(DNS_DB_VALID(db));
    186 
    187 	if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) {
    188 		return (true);
    189 	}
    190 
    191 	return (false);
    192 }
    193 
    194 bool
    195 dns_db_isstub(dns_db_t *db) {
    196 	/*
    197 	 * Does 'db' have stub semantics?
    198 	 */
    199 
    200 	REQUIRE(DNS_DB_VALID(db));
    201 
    202 	if ((db->attributes & DNS_DBATTR_STUB) != 0) {
    203 		return (true);
    204 	}
    205 
    206 	return (false);
    207 }
    208 
    209 bool
    210 dns_db_isdnssec(dns_db_t *db) {
    211 	/*
    212 	 * Is 'db' secure or partially secure?
    213 	 */
    214 
    215 	REQUIRE(DNS_DB_VALID(db));
    216 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    217 
    218 	if (db->methods->isdnssec != NULL) {
    219 		return ((db->methods->isdnssec)(db));
    220 	}
    221 	return ((db->methods->issecure)(db));
    222 }
    223 
    224 bool
    225 dns_db_issecure(dns_db_t *db) {
    226 	/*
    227 	 * Is 'db' secure?
    228 	 */
    229 
    230 	REQUIRE(DNS_DB_VALID(db));
    231 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    232 
    233 	return ((db->methods->issecure)(db));
    234 }
    235 
    236 bool
    237 dns_db_ispersistent(dns_db_t *db) {
    238 	/*
    239 	 * Is 'db' persistent?
    240 	 */
    241 
    242 	REQUIRE(DNS_DB_VALID(db));
    243 
    244 	return ((db->methods->ispersistent)(db));
    245 }
    246 
    247 dns_name_t *
    248 dns_db_origin(dns_db_t *db) {
    249 	/*
    250 	 * The origin of the database.
    251 	 */
    252 
    253 	REQUIRE(DNS_DB_VALID(db));
    254 
    255 	return (&db->origin);
    256 }
    257 
    258 dns_rdataclass_t
    259 dns_db_class(dns_db_t *db) {
    260 	/*
    261 	 * The class of the database.
    262 	 */
    263 
    264 	REQUIRE(DNS_DB_VALID(db));
    265 
    266 	return (db->rdclass);
    267 }
    268 
    269 isc_result_t
    270 dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    271 	/*
    272 	 * Begin loading 'db'.
    273 	 */
    274 
    275 	REQUIRE(DNS_DB_VALID(db));
    276 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    277 
    278 	return ((db->methods->beginload)(db, callbacks));
    279 }
    280 
    281 isc_result_t
    282 dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
    283 	dns_dbonupdatelistener_t *listener;
    284 
    285 	/*
    286 	 * Finish loading 'db'.
    287 	 */
    288 
    289 	REQUIRE(DNS_DB_VALID(db));
    290 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
    291 	REQUIRE(callbacks->add_private != NULL);
    292 
    293 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
    294 	     listener = ISC_LIST_NEXT(listener, link))
    295 	{
    296 		listener->onupdate(db, listener->onupdate_arg);
    297 	}
    298 
    299 	return ((db->methods->endload)(db, callbacks));
    300 }
    301 
    302 isc_result_t
    303 dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
    304 	    unsigned int options) {
    305 	isc_result_t result, eresult;
    306 	dns_rdatacallbacks_t callbacks;
    307 
    308 	/*
    309 	 * Load master file 'filename' into 'db'.
    310 	 */
    311 
    312 	REQUIRE(DNS_DB_VALID(db));
    313 
    314 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
    315 		options |= DNS_MASTER_AGETTL;
    316 	}
    317 
    318 	dns_rdatacallbacks_init(&callbacks);
    319 	result = dns_db_beginload(db, &callbacks);
    320 	if (result != ISC_R_SUCCESS) {
    321 		return (result);
    322 	}
    323 	result = dns_master_loadfile(filename, &db->origin, &db->origin,
    324 				     db->rdclass, options, 0, &callbacks, NULL,
    325 				     NULL, db->mctx, format, 0);
    326 	eresult = dns_db_endload(db, &callbacks);
    327 	/*
    328 	 * We always call dns_db_endload(), but we only want to return its
    329 	 * result if dns_master_loadfile() succeeded.  If dns_master_loadfile()
    330 	 * failed, we want to return the result code it gave us.
    331 	 */
    332 	if (eresult != ISC_R_SUCCESS &&
    333 	    (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
    334 	{
    335 		result = eresult;
    336 	}
    337 
    338 	return (result);
    339 }
    340 
    341 isc_result_t
    342 dns_db_serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file) {
    343 	REQUIRE(DNS_DB_VALID(db));
    344 	if (db->methods->serialize == NULL) {
    345 		return (ISC_R_NOTIMPLEMENTED);
    346 	}
    347 	return ((db->methods->serialize)(db, version, file));
    348 }
    349 
    350 isc_result_t
    351 dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
    352 	return ((db->methods->dump)(db, version, filename,
    353 				    dns_masterformat_text));
    354 }
    355 
    356 /***
    357  *** Version Methods
    358  ***/
    359 
    360 void
    361 dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
    362 	/*
    363 	 * Open the current version for reading.
    364 	 */
    365 
    366 	REQUIRE(DNS_DB_VALID(db));
    367 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    368 	REQUIRE(versionp != NULL && *versionp == NULL);
    369 
    370 	(db->methods->currentversion)(db, versionp);
    371 }
    372 
    373 isc_result_t
    374 dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
    375 	/*
    376 	 * Open a new version for reading and writing.
    377 	 */
    378 
    379 	REQUIRE(DNS_DB_VALID(db));
    380 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    381 	REQUIRE(versionp != NULL && *versionp == NULL);
    382 
    383 	return ((db->methods->newversion)(db, versionp));
    384 }
    385 
    386 void
    387 dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
    388 		     dns_dbversion_t **targetp) {
    389 	/*
    390 	 * Attach '*targetp' to 'source'.
    391 	 */
    392 
    393 	REQUIRE(DNS_DB_VALID(db));
    394 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    395 	REQUIRE(source != NULL);
    396 	REQUIRE(targetp != NULL && *targetp == NULL);
    397 
    398 	(db->methods->attachversion)(db, source, targetp);
    399 
    400 	ENSURE(*targetp != NULL);
    401 }
    402 
    403 void
    404 dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
    405 	dns_dbonupdatelistener_t *listener;
    406 
    407 	/*
    408 	 * Close version '*versionp'.
    409 	 */
    410 
    411 	REQUIRE(DNS_DB_VALID(db));
    412 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
    413 	REQUIRE(versionp != NULL && *versionp != NULL);
    414 
    415 	(db->methods->closeversion)(db, versionp, commit);
    416 
    417 	if (commit) {
    418 		for (listener = ISC_LIST_HEAD(db->update_listeners);
    419 		     listener != NULL; listener = ISC_LIST_NEXT(listener, link))
    420 		{
    421 			listener->onupdate(db, listener->onupdate_arg);
    422 		}
    423 	}
    424 
    425 	ENSURE(*versionp == NULL);
    426 }
    427 
    428 /***
    429  *** Node Methods
    430  ***/
    431 
    432 isc_result_t
    433 dns_db_findnode(dns_db_t *db, const dns_name_t *name, bool create,
    434 		dns_dbnode_t **nodep) {
    435 	/*
    436 	 * Find the node with name 'name'.
    437 	 */
    438 
    439 	REQUIRE(DNS_DB_VALID(db));
    440 	REQUIRE(nodep != NULL && *nodep == NULL);
    441 
    442 	if (db->methods->findnode != NULL) {
    443 		return ((db->methods->findnode)(db, name, create, nodep));
    444 	} else {
    445 		return ((db->methods->findnodeext)(db, name, create, NULL, NULL,
    446 						   nodep));
    447 	}
    448 }
    449 
    450 isc_result_t
    451 dns_db_findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
    452 		   dns_clientinfomethods_t *methods,
    453 		   dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep) {
    454 	/*
    455 	 * Find the node with name 'name', passing 'arg' to the database
    456 	 * implementation.
    457 	 */
    458 
    459 	REQUIRE(DNS_DB_VALID(db));
    460 	REQUIRE(nodep != NULL && *nodep == NULL);
    461 
    462 	if (db->methods->findnodeext != NULL) {
    463 		return ((db->methods->findnodeext)(db, name, create, methods,
    464 						   clientinfo, nodep));
    465 	} else {
    466 		return ((db->methods->findnode)(db, name, create, nodep));
    467 	}
    468 }
    469 
    470 isc_result_t
    471 dns_db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
    472 		     dns_dbnode_t **nodep) {
    473 	/*
    474 	 * Find the node with name 'name'.
    475 	 */
    476 
    477 	REQUIRE(DNS_DB_VALID(db));
    478 	REQUIRE(nodep != NULL && *nodep == NULL);
    479 
    480 	return ((db->methods->findnsec3node)(db, name, create, nodep));
    481 }
    482 
    483 isc_result_t
    484 dns_db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
    485 	    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
    486 	    dns_dbnode_t **nodep, dns_name_t *foundname,
    487 	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
    488 	/*
    489 	 * Find the best match for 'name' and 'type' in version 'version'
    490 	 * of 'db'.
    491 	 */
    492 
    493 	REQUIRE(DNS_DB_VALID(db));
    494 	REQUIRE(type != dns_rdatatype_rrsig);
    495 	REQUIRE(nodep == NULL || *nodep == NULL);
    496 	REQUIRE(dns_name_hasbuffer(foundname));
    497 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
    498 				     !dns_rdataset_isassociated(rdataset)));
    499 	REQUIRE(sigrdataset == NULL ||
    500 		(DNS_RDATASET_VALID(sigrdataset) &&
    501 		 !dns_rdataset_isassociated(sigrdataset)));
    502 
    503 	if (db->methods->find != NULL) {
    504 		return ((db->methods->find)(db, name, version, type, options,
    505 					    now, nodep, foundname, rdataset,
    506 					    sigrdataset));
    507 	} else {
    508 		return ((db->methods->findext)(db, name, version, type, options,
    509 					       now, nodep, foundname, NULL,
    510 					       NULL, rdataset, sigrdataset));
    511 	}
    512 }
    513 
    514 isc_result_t
    515 dns_db_findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
    516 	       dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
    517 	       dns_dbnode_t **nodep, dns_name_t *foundname,
    518 	       dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
    519 	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
    520 	/*
    521 	 * Find the best match for 'name' and 'type' in version 'version'
    522 	 * of 'db', passing in 'arg'.
    523 	 */
    524 
    525 	REQUIRE(DNS_DB_VALID(db));
    526 	REQUIRE(type != dns_rdatatype_rrsig);
    527 	REQUIRE(nodep == NULL || *nodep == NULL);
    528 	REQUIRE(dns_name_hasbuffer(foundname));
    529 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
    530 				     !dns_rdataset_isassociated(rdataset)));
    531 	REQUIRE(sigrdataset == NULL ||
    532 		(DNS_RDATASET_VALID(sigrdataset) &&
    533 		 !dns_rdataset_isassociated(sigrdataset)));
    534 
    535 	if (db->methods->findext != NULL) {
    536 		return ((db->methods->findext)(
    537 			db, name, version, type, options, now, nodep, foundname,
    538 			methods, clientinfo, rdataset, sigrdataset));
    539 	} else {
    540 		return ((db->methods->find)(db, name, version, type, options,
    541 					    now, nodep, foundname, rdataset,
    542 					    sigrdataset));
    543 	}
    544 }
    545 
    546 isc_result_t
    547 dns_db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
    548 		   isc_stdtime_t now, dns_dbnode_t **nodep,
    549 		   dns_name_t *foundname, dns_name_t *dcname,
    550 		   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
    551 	/*
    552 	 * Find the deepest known zonecut which encloses 'name' in 'db'.
    553 	 * foundname is the zonecut, dcname is the deepest name we have
    554 	 * in database that is part of queried name.
    555 	 */
    556 
    557 	REQUIRE(DNS_DB_VALID(db));
    558 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
    559 	REQUIRE(nodep == NULL || *nodep == NULL);
    560 	REQUIRE(dns_name_hasbuffer(foundname));
    561 	REQUIRE(sigrdataset == NULL ||
    562 		(DNS_RDATASET_VALID(sigrdataset) &&
    563 		 !dns_rdataset_isassociated(sigrdataset)));
    564 
    565 	return ((db->methods->findzonecut)(db, name, options, now, nodep,
    566 					   foundname, dcname, rdataset,
    567 					   sigrdataset));
    568 }
    569 
    570 void
    571 dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
    572 	/*
    573 	 * Attach *targetp to source.
    574 	 */
    575 
    576 	REQUIRE(DNS_DB_VALID(db));
    577 	REQUIRE(source != NULL);
    578 	REQUIRE(targetp != NULL && *targetp == NULL);
    579 
    580 	(db->methods->attachnode)(db, source, targetp);
    581 }
    582 
    583 void
    584 dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
    585 	/*
    586 	 * Detach *nodep from its node.
    587 	 */
    588 
    589 	REQUIRE(DNS_DB_VALID(db));
    590 	REQUIRE(nodep != NULL && *nodep != NULL);
    591 
    592 	(db->methods->detachnode)(db, nodep);
    593 
    594 	ENSURE(*nodep == NULL);
    595 }
    596 
    597 void
    598 dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
    599 		    dns_dbnode_t **targetp) {
    600 	REQUIRE(DNS_DB_VALID(db));
    601 	REQUIRE(targetp != NULL && *targetp == NULL);
    602 	/*
    603 	 * This doesn't check the implementation magic.  If we find that
    604 	 * we need such checks in future then this will be done in the
    605 	 * method.
    606 	 */
    607 	REQUIRE(sourcep != NULL && *sourcep != NULL);
    608 
    609 	UNUSED(db);
    610 
    611 	if (db->methods->transfernode == NULL) {
    612 		*targetp = *sourcep;
    613 		*sourcep = NULL;
    614 	} else {
    615 		(db->methods->transfernode)(db, sourcep, targetp);
    616 	}
    617 
    618 	ENSURE(*sourcep == NULL);
    619 }
    620 
    621 isc_result_t
    622 dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
    623 	/*
    624 	 * Mark as stale all records at 'node' which expire at or before 'now'.
    625 	 */
    626 
    627 	REQUIRE(DNS_DB_VALID(db));
    628 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
    629 	REQUIRE(node != NULL);
    630 
    631 	return ((db->methods->expirenode)(db, node, now));
    632 }
    633 
    634 void
    635 dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
    636 	/*
    637 	 * Print a textual representation of the contents of the node to
    638 	 * 'out'.
    639 	 */
    640 
    641 	REQUIRE(DNS_DB_VALID(db));
    642 	REQUIRE(node != NULL);
    643 
    644 	(db->methods->printnode)(db, node, out);
    645 }
    646 
    647 /***
    648  *** DB Iterator Creation
    649  ***/
    650 
    651 isc_result_t
    652 dns_db_createiterator(dns_db_t *db, unsigned int flags,
    653 		      dns_dbiterator_t **iteratorp) {
    654 	/*
    655 	 * Create an iterator for version 'version' of 'db'.
    656 	 */
    657 
    658 	REQUIRE(DNS_DB_VALID(db));
    659 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
    660 
    661 	return (db->methods->createiterator(db, flags, iteratorp));
    662 }
    663 
    664 /***
    665  *** Rdataset Methods
    666  ***/
    667 
    668 isc_result_t
    669 dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    670 		    dns_rdatatype_t type, dns_rdatatype_t covers,
    671 		    isc_stdtime_t now, dns_rdataset_t *rdataset,
    672 		    dns_rdataset_t *sigrdataset) {
    673 	REQUIRE(DNS_DB_VALID(db));
    674 	REQUIRE(node != NULL);
    675 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    676 	REQUIRE(!dns_rdataset_isassociated(rdataset));
    677 	REQUIRE(covers == 0 || type == dns_rdatatype_rrsig);
    678 	REQUIRE(type != dns_rdatatype_any);
    679 	REQUIRE(sigrdataset == NULL ||
    680 		(DNS_RDATASET_VALID(sigrdataset) &&
    681 		 !dns_rdataset_isassociated(sigrdataset)));
    682 
    683 	return ((db->methods->findrdataset)(db, node, version, type, covers,
    684 					    now, rdataset, sigrdataset));
    685 }
    686 
    687 isc_result_t
    688 dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    689 		    unsigned int options, isc_stdtime_t now,
    690 		    dns_rdatasetiter_t **iteratorp) {
    691 	/*
    692 	 * Make '*iteratorp' an rdataset iteratator for all rdatasets at
    693 	 * 'node' in version 'version' of 'db'.
    694 	 */
    695 
    696 	REQUIRE(DNS_DB_VALID(db));
    697 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
    698 
    699 	return ((db->methods->allrdatasets)(db, node, version, options, now,
    700 					    iteratorp));
    701 }
    702 
    703 isc_result_t
    704 dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    705 		   isc_stdtime_t now, dns_rdataset_t *rdataset,
    706 		   unsigned int options, dns_rdataset_t *addedrdataset) {
    707 	/*
    708 	 * Add 'rdataset' to 'node' in version 'version' of 'db'.
    709 	 */
    710 
    711 	REQUIRE(DNS_DB_VALID(db));
    712 	REQUIRE(node != NULL);
    713 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
    714 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
    715 		 (options & DNS_DBADD_MERGE) == 0));
    716 	REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
    717 		(options & DNS_DBADD_MERGE) != 0);
    718 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    719 	REQUIRE(dns_rdataset_isassociated(rdataset));
    720 	REQUIRE(rdataset->rdclass == db->rdclass);
    721 	REQUIRE(addedrdataset == NULL ||
    722 		(DNS_RDATASET_VALID(addedrdataset) &&
    723 		 !dns_rdataset_isassociated(addedrdataset)));
    724 
    725 	return ((db->methods->addrdataset)(db, node, version, now, rdataset,
    726 					   options, addedrdataset));
    727 }
    728 
    729 isc_result_t
    730 dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
    731 			dns_dbversion_t *version, dns_rdataset_t *rdataset,
    732 			unsigned int options, dns_rdataset_t *newrdataset) {
    733 	/*
    734 	 * Remove any rdata in 'rdataset' from 'node' in version 'version' of
    735 	 * 'db'.
    736 	 */
    737 
    738 	REQUIRE(DNS_DB_VALID(db));
    739 	REQUIRE(node != NULL);
    740 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
    741 	REQUIRE(DNS_RDATASET_VALID(rdataset));
    742 	REQUIRE(dns_rdataset_isassociated(rdataset));
    743 	REQUIRE(rdataset->rdclass == db->rdclass);
    744 	REQUIRE(newrdataset == NULL ||
    745 		(DNS_RDATASET_VALID(newrdataset) &&
    746 		 !dns_rdataset_isassociated(newrdataset)));
    747 
    748 	return ((db->methods->subtractrdataset)(db, node, version, rdataset,
    749 						options, newrdataset));
    750 }
    751 
    752 isc_result_t
    753 dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
    754 		      dns_dbversion_t *version, dns_rdatatype_t type,
    755 		      dns_rdatatype_t covers) {
    756 	/*
    757 	 * Make it so that no rdataset of type 'type' exists at 'node' in
    758 	 * version version 'version' of 'db'.
    759 	 */
    760 
    761 	REQUIRE(DNS_DB_VALID(db));
    762 	REQUIRE(node != NULL);
    763 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
    764 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
    765 
    766 	return ((db->methods->deleterdataset)(db, node, version, type, covers));
    767 }
    768 
    769 void
    770 dns_db_overmem(dns_db_t *db, bool overmem) {
    771 	REQUIRE(DNS_DB_VALID(db));
    772 
    773 	(db->methods->overmem)(db, overmem);
    774 }
    775 
    776 isc_result_t
    777 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
    778 	isc_result_t result;
    779 	dns_dbnode_t *node = NULL;
    780 	dns_rdataset_t rdataset;
    781 	dns_rdata_t rdata = DNS_RDATA_INIT;
    782 	isc_buffer_t buffer;
    783 
    784 	REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
    785 
    786 	result = dns_db_findnode(db, dns_db_origin(db), false, &node);
    787 	if (result != ISC_R_SUCCESS) {
    788 		return (result);
    789 	}
    790 
    791 	dns_rdataset_init(&rdataset);
    792 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
    793 				     (isc_stdtime_t)0, &rdataset, NULL);
    794 	if (result != ISC_R_SUCCESS) {
    795 		goto freenode;
    796 	}
    797 
    798 	result = dns_rdataset_first(&rdataset);
    799 	if (result != ISC_R_SUCCESS) {
    800 		goto freerdataset;
    801 	}
    802 	dns_rdataset_current(&rdataset, &rdata);
    803 	result = dns_rdataset_next(&rdataset);
    804 	INSIST(result == ISC_R_NOMORE);
    805 
    806 	INSIST(rdata.length > 20);
    807 	isc_buffer_init(&buffer, rdata.data, rdata.length);
    808 	isc_buffer_add(&buffer, rdata.length);
    809 	isc_buffer_forward(&buffer, rdata.length - 20);
    810 	*serialp = isc_buffer_getuint32(&buffer);
    811 
    812 	result = ISC_R_SUCCESS;
    813 
    814 freerdataset:
    815 	dns_rdataset_disassociate(&rdataset);
    816 
    817 freenode:
    818 	dns_db_detachnode(db, &node);
    819 	return (result);
    820 }
    821 
    822 unsigned int
    823 dns_db_nodecount(dns_db_t *db) {
    824 	REQUIRE(DNS_DB_VALID(db));
    825 
    826 	return ((db->methods->nodecount)(db));
    827 }
    828 
    829 size_t
    830 dns_db_hashsize(dns_db_t *db) {
    831 	REQUIRE(DNS_DB_VALID(db));
    832 
    833 	if (db->methods->hashsize == NULL) {
    834 		return (0);
    835 	}
    836 
    837 	return ((db->methods->hashsize)(db));
    838 }
    839 
    840 isc_result_t
    841 dns_db_adjusthashsize(dns_db_t *db, size_t size) {
    842 	REQUIRE(DNS_DB_VALID(db));
    843 
    844 	if (db->methods->adjusthashsize != NULL) {
    845 		return ((db->methods->adjusthashsize)(db, size));
    846 	}
    847 
    848 	return (ISC_R_NOTIMPLEMENTED);
    849 }
    850 
    851 void
    852 dns_db_settask(dns_db_t *db, isc_task_t *task) {
    853 	REQUIRE(DNS_DB_VALID(db));
    854 
    855 	(db->methods->settask)(db, task);
    856 }
    857 
    858 isc_result_t
    859 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
    860 		isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
    861 	dns_dbimplementation_t *imp;
    862 
    863 	REQUIRE(name != NULL);
    864 	REQUIRE(dbimp != NULL && *dbimp == NULL);
    865 
    866 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
    867 
    868 	RWLOCK(&implock, isc_rwlocktype_write);
    869 	imp = impfind(name);
    870 	if (imp != NULL) {
    871 		RWUNLOCK(&implock, isc_rwlocktype_write);
    872 		return (ISC_R_EXISTS);
    873 	}
    874 
    875 	imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
    876 	imp->name = name;
    877 	imp->create = create;
    878 	imp->mctx = NULL;
    879 	imp->driverarg = driverarg;
    880 	isc_mem_attach(mctx, &imp->mctx);
    881 	ISC_LINK_INIT(imp, link);
    882 	ISC_LIST_APPEND(implementations, imp, link);
    883 	RWUNLOCK(&implock, isc_rwlocktype_write);
    884 
    885 	*dbimp = imp;
    886 
    887 	return (ISC_R_SUCCESS);
    888 }
    889 
    890 void
    891 dns_db_unregister(dns_dbimplementation_t **dbimp) {
    892 	dns_dbimplementation_t *imp;
    893 
    894 	REQUIRE(dbimp != NULL && *dbimp != NULL);
    895 
    896 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
    897 
    898 	imp = *dbimp;
    899 	*dbimp = NULL;
    900 	RWLOCK(&implock, isc_rwlocktype_write);
    901 	ISC_LIST_UNLINK(implementations, imp, link);
    902 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
    903 	RWUNLOCK(&implock, isc_rwlocktype_write);
    904 	ENSURE(*dbimp == NULL);
    905 }
    906 
    907 isc_result_t
    908 dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
    909 	REQUIRE(DNS_DB_VALID(db));
    910 	REQUIRE(dns_db_iszone(db));
    911 	REQUIRE(nodep != NULL && *nodep == NULL);
    912 
    913 	if (db->methods->getoriginnode != NULL) {
    914 		return ((db->methods->getoriginnode)(db, nodep));
    915 	}
    916 
    917 	return (ISC_R_NOTFOUND);
    918 }
    919 
    920 dns_stats_t *
    921 dns_db_getrrsetstats(dns_db_t *db) {
    922 	REQUIRE(DNS_DB_VALID(db));
    923 
    924 	if (db->methods->getrrsetstats != NULL) {
    925 		return ((db->methods->getrrsetstats)(db));
    926 	}
    927 
    928 	return (NULL);
    929 }
    930 
    931 isc_result_t
    932 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
    933 	REQUIRE(DNS_DB_VALID(db));
    934 
    935 	if (db->methods->setcachestats != NULL) {
    936 		return ((db->methods->setcachestats)(db, stats));
    937 	}
    938 
    939 	return (ISC_R_NOTIMPLEMENTED);
    940 }
    941 
    942 isc_result_t
    943 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
    944 			  dns_hash_t *hash, uint8_t *flags,
    945 			  uint16_t *iterations, unsigned char *salt,
    946 			  size_t *salt_length) {
    947 	REQUIRE(DNS_DB_VALID(db));
    948 	REQUIRE(dns_db_iszone(db));
    949 
    950 	if (db->methods->getnsec3parameters != NULL) {
    951 		return ((db->methods->getnsec3parameters)(db, version, hash,
    952 							  flags, iterations,
    953 							  salt, salt_length));
    954 	}
    955 
    956 	return (ISC_R_NOTFOUND);
    957 }
    958 
    959 isc_result_t
    960 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
    961 	       uint64_t *bytes) {
    962 	REQUIRE(DNS_DB_VALID(db));
    963 	REQUIRE(dns_db_iszone(db));
    964 
    965 	if (db->methods->getsize != NULL) {
    966 		return ((db->methods->getsize)(db, version, records, bytes));
    967 	}
    968 
    969 	return (ISC_R_NOTFOUND);
    970 }
    971 
    972 isc_result_t
    973 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
    974 		      isc_stdtime_t resign) {
    975 	if (db->methods->setsigningtime != NULL) {
    976 		return ((db->methods->setsigningtime)(db, rdataset, resign));
    977 	}
    978 	return (ISC_R_NOTIMPLEMENTED);
    979 }
    980 
    981 isc_result_t
    982 dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
    983 		      dns_name_t *name) {
    984 	if (db->methods->getsigningtime != NULL) {
    985 		return ((db->methods->getsigningtime)(db, rdataset, name));
    986 	}
    987 	return (ISC_R_NOTFOUND);
    988 }
    989 
    990 void
    991 dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
    992 		dns_dbversion_t *version) {
    993 	if (db->methods->resigned != NULL) {
    994 		(db->methods->resigned)(db, rdataset, version);
    995 	}
    996 }
    997 
    998 /*
    999  * Attach a database to policy zone databases.
   1000  * This should only happen when the caller has already ensured that
   1001  * it is dealing with a database that understands response policy zones.
   1002  */
   1003 void
   1004 dns_db_rpz_attach(dns_db_t *db, void *rpzs, uint8_t rpz_num) {
   1005 	REQUIRE(db->methods->rpz_attach != NULL);
   1006 	(db->methods->rpz_attach)(db, rpzs, rpz_num);
   1007 }
   1008 
   1009 /*
   1010  * Finish loading a response policy zone.
   1011  */
   1012 isc_result_t
   1013 dns_db_rpz_ready(dns_db_t *db) {
   1014 	if (db->methods->rpz_ready == NULL) {
   1015 		return (ISC_R_SUCCESS);
   1016 	}
   1017 	return ((db->methods->rpz_ready)(db));
   1018 }
   1019 
   1020 /*
   1021  * Attach a notify-on-update function the database
   1022  */
   1023 isc_result_t
   1024 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
   1025 			     void *fn_arg) {
   1026 	dns_dbonupdatelistener_t *listener;
   1027 
   1028 	REQUIRE(db != NULL);
   1029 	REQUIRE(fn != NULL);
   1030 
   1031 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
   1032 	     listener = ISC_LIST_NEXT(listener, link))
   1033 	{
   1034 		if ((listener->onupdate == fn) &&
   1035 		    (listener->onupdate_arg == fn_arg))
   1036 		{
   1037 			return (ISC_R_SUCCESS);
   1038 		}
   1039 	}
   1040 
   1041 	listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t));
   1042 
   1043 	listener->onupdate = fn;
   1044 	listener->onupdate_arg = fn_arg;
   1045 
   1046 	ISC_LINK_INIT(listener, link);
   1047 	ISC_LIST_APPEND(db->update_listeners, listener, link);
   1048 
   1049 	return (ISC_R_SUCCESS);
   1050 }
   1051 
   1052 isc_result_t
   1053 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
   1054 			       void *fn_arg) {
   1055 	dns_dbonupdatelistener_t *listener;
   1056 
   1057 	REQUIRE(db != NULL);
   1058 
   1059 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
   1060 	     listener = ISC_LIST_NEXT(listener, link))
   1061 	{
   1062 		if ((listener->onupdate == fn) &&
   1063 		    (listener->onupdate_arg == fn_arg))
   1064 		{
   1065 			ISC_LIST_UNLINK(db->update_listeners, listener, link);
   1066 			isc_mem_put(db->mctx, listener,
   1067 				    sizeof(dns_dbonupdatelistener_t));
   1068 			return (ISC_R_SUCCESS);
   1069 		}
   1070 	}
   1071 
   1072 	return (ISC_R_NOTFOUND);
   1073 }
   1074 
   1075 isc_result_t
   1076 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
   1077 	REQUIRE(db != NULL);
   1078 	REQUIRE(node != NULL);
   1079 	REQUIRE(name != NULL);
   1080 
   1081 	if (db->methods->nodefullname == NULL) {
   1082 		return (ISC_R_NOTIMPLEMENTED);
   1083 	}
   1084 	return ((db->methods->nodefullname)(db, node, name));
   1085 }
   1086 
   1087 isc_result_t
   1088 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
   1089 	REQUIRE(DNS_DB_VALID(db));
   1090 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1091 
   1092 	if (db->methods->setservestalettl != NULL) {
   1093 		return ((db->methods->setservestalettl)(db, ttl));
   1094 	}
   1095 	return (ISC_R_NOTIMPLEMENTED);
   1096 }
   1097 
   1098 isc_result_t
   1099 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
   1100 	REQUIRE(DNS_DB_VALID(db));
   1101 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1102 
   1103 	if (db->methods->getservestalettl != NULL) {
   1104 		return ((db->methods->getservestalettl)(db, ttl));
   1105 	}
   1106 	return (ISC_R_NOTIMPLEMENTED);
   1107 }
   1108 
   1109 isc_result_t
   1110 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
   1111 	REQUIRE(DNS_DB_VALID(db));
   1112 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1113 
   1114 	if (db->methods->setservestalerefresh != NULL) {
   1115 		return ((db->methods->setservestalerefresh)(db, interval));
   1116 	}
   1117 	return (ISC_R_NOTIMPLEMENTED);
   1118 }
   1119 
   1120 isc_result_t
   1121 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
   1122 	REQUIRE(DNS_DB_VALID(db));
   1123 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
   1124 
   1125 	if (db->methods->getservestalerefresh != NULL) {
   1126 		return ((db->methods->getservestalerefresh)(db, interval));
   1127 	}
   1128 	return (ISC_R_NOTIMPLEMENTED);
   1129 }
   1130 
   1131 isc_result_t
   1132 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
   1133 	REQUIRE(dns_db_iszone(db));
   1134 	REQUIRE(stats != NULL);
   1135 
   1136 	if (db->methods->setgluecachestats != NULL) {
   1137 		return ((db->methods->setgluecachestats)(db, stats));
   1138 	}
   1139 
   1140 	return (ISC_R_NOTIMPLEMENTED);
   1141 }
   1142