xref: /netbsd/external/mpl/bind/dist/lib/dns/db.c (revision c0b5d9fb)
1 /*	$NetBSD: db.c,v 1.8 2022/09/23 12:15:29 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/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 		    isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) {
690 	/*
691 	 * Make '*iteratorp' an rdataset iteratator for all rdatasets at
692 	 * 'node' in version 'version' of 'db'.
693 	 */
694 
695 	REQUIRE(DNS_DB_VALID(db));
696 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
697 
698 	return ((db->methods->allrdatasets)(db, node, version, now, iteratorp));
699 }
700 
701 isc_result_t
702 dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
703 		   isc_stdtime_t now, dns_rdataset_t *rdataset,
704 		   unsigned int options, dns_rdataset_t *addedrdataset) {
705 	/*
706 	 * Add 'rdataset' to 'node' in version 'version' of 'db'.
707 	 */
708 
709 	REQUIRE(DNS_DB_VALID(db));
710 	REQUIRE(node != NULL);
711 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
712 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
713 		 (options & DNS_DBADD_MERGE) == 0));
714 	REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
715 		(options & DNS_DBADD_MERGE) != 0);
716 	REQUIRE(DNS_RDATASET_VALID(rdataset));
717 	REQUIRE(dns_rdataset_isassociated(rdataset));
718 	REQUIRE(rdataset->rdclass == db->rdclass);
719 	REQUIRE(addedrdataset == NULL ||
720 		(DNS_RDATASET_VALID(addedrdataset) &&
721 		 !dns_rdataset_isassociated(addedrdataset)));
722 
723 	return ((db->methods->addrdataset)(db, node, version, now, rdataset,
724 					   options, addedrdataset));
725 }
726 
727 isc_result_t
728 dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
729 			dns_dbversion_t *version, dns_rdataset_t *rdataset,
730 			unsigned int options, dns_rdataset_t *newrdataset) {
731 	/*
732 	 * Remove any rdata in 'rdataset' from 'node' in version 'version' of
733 	 * 'db'.
734 	 */
735 
736 	REQUIRE(DNS_DB_VALID(db));
737 	REQUIRE(node != NULL);
738 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
739 	REQUIRE(DNS_RDATASET_VALID(rdataset));
740 	REQUIRE(dns_rdataset_isassociated(rdataset));
741 	REQUIRE(rdataset->rdclass == db->rdclass);
742 	REQUIRE(newrdataset == NULL ||
743 		(DNS_RDATASET_VALID(newrdataset) &&
744 		 !dns_rdataset_isassociated(newrdataset)));
745 
746 	return ((db->methods->subtractrdataset)(db, node, version, rdataset,
747 						options, newrdataset));
748 }
749 
750 isc_result_t
751 dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
752 		      dns_dbversion_t *version, dns_rdatatype_t type,
753 		      dns_rdatatype_t covers) {
754 	/*
755 	 * Make it so that no rdataset of type 'type' exists at 'node' in
756 	 * version version 'version' of 'db'.
757 	 */
758 
759 	REQUIRE(DNS_DB_VALID(db));
760 	REQUIRE(node != NULL);
761 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
762 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
763 
764 	return ((db->methods->deleterdataset)(db, node, version, type, covers));
765 }
766 
767 void
768 dns_db_overmem(dns_db_t *db, bool overmem) {
769 	REQUIRE(DNS_DB_VALID(db));
770 
771 	(db->methods->overmem)(db, overmem);
772 }
773 
774 isc_result_t
775 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
776 	isc_result_t result;
777 	dns_dbnode_t *node = NULL;
778 	dns_rdataset_t rdataset;
779 	dns_rdata_t rdata = DNS_RDATA_INIT;
780 	isc_buffer_t buffer;
781 
782 	REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
783 
784 	result = dns_db_findnode(db, dns_db_origin(db), false, &node);
785 	if (result != ISC_R_SUCCESS) {
786 		return (result);
787 	}
788 
789 	dns_rdataset_init(&rdataset);
790 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
791 				     (isc_stdtime_t)0, &rdataset, NULL);
792 	if (result != ISC_R_SUCCESS) {
793 		goto freenode;
794 	}
795 
796 	result = dns_rdataset_first(&rdataset);
797 	if (result != ISC_R_SUCCESS) {
798 		goto freerdataset;
799 	}
800 	dns_rdataset_current(&rdataset, &rdata);
801 	result = dns_rdataset_next(&rdataset);
802 	INSIST(result == ISC_R_NOMORE);
803 
804 	INSIST(rdata.length > 20);
805 	isc_buffer_init(&buffer, rdata.data, rdata.length);
806 	isc_buffer_add(&buffer, rdata.length);
807 	isc_buffer_forward(&buffer, rdata.length - 20);
808 	*serialp = isc_buffer_getuint32(&buffer);
809 
810 	result = ISC_R_SUCCESS;
811 
812 freerdataset:
813 	dns_rdataset_disassociate(&rdataset);
814 
815 freenode:
816 	dns_db_detachnode(db, &node);
817 	return (result);
818 }
819 
820 unsigned int
821 dns_db_nodecount(dns_db_t *db) {
822 	REQUIRE(DNS_DB_VALID(db));
823 
824 	return ((db->methods->nodecount)(db));
825 }
826 
827 size_t
828 dns_db_hashsize(dns_db_t *db) {
829 	REQUIRE(DNS_DB_VALID(db));
830 
831 	if (db->methods->hashsize == NULL) {
832 		return (0);
833 	}
834 
835 	return ((db->methods->hashsize)(db));
836 }
837 
838 isc_result_t
839 dns_db_adjusthashsize(dns_db_t *db, size_t size) {
840 	REQUIRE(DNS_DB_VALID(db));
841 
842 	if (db->methods->adjusthashsize != NULL) {
843 		return ((db->methods->adjusthashsize)(db, size));
844 	}
845 
846 	return (ISC_R_NOTIMPLEMENTED);
847 }
848 
849 void
850 dns_db_settask(dns_db_t *db, isc_task_t *task) {
851 	REQUIRE(DNS_DB_VALID(db));
852 
853 	(db->methods->settask)(db, task);
854 }
855 
856 isc_result_t
857 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
858 		isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
859 	dns_dbimplementation_t *imp;
860 
861 	REQUIRE(name != NULL);
862 	REQUIRE(dbimp != NULL && *dbimp == NULL);
863 
864 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
865 
866 	RWLOCK(&implock, isc_rwlocktype_write);
867 	imp = impfind(name);
868 	if (imp != NULL) {
869 		RWUNLOCK(&implock, isc_rwlocktype_write);
870 		return (ISC_R_EXISTS);
871 	}
872 
873 	imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
874 	imp->name = name;
875 	imp->create = create;
876 	imp->mctx = NULL;
877 	imp->driverarg = driverarg;
878 	isc_mem_attach(mctx, &imp->mctx);
879 	ISC_LINK_INIT(imp, link);
880 	ISC_LIST_APPEND(implementations, imp, link);
881 	RWUNLOCK(&implock, isc_rwlocktype_write);
882 
883 	*dbimp = imp;
884 
885 	return (ISC_R_SUCCESS);
886 }
887 
888 void
889 dns_db_unregister(dns_dbimplementation_t **dbimp) {
890 	dns_dbimplementation_t *imp;
891 
892 	REQUIRE(dbimp != NULL && *dbimp != NULL);
893 
894 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
895 
896 	imp = *dbimp;
897 	*dbimp = NULL;
898 	RWLOCK(&implock, isc_rwlocktype_write);
899 	ISC_LIST_UNLINK(implementations, imp, link);
900 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
901 	RWUNLOCK(&implock, isc_rwlocktype_write);
902 	ENSURE(*dbimp == NULL);
903 }
904 
905 isc_result_t
906 dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
907 	REQUIRE(DNS_DB_VALID(db));
908 	REQUIRE(dns_db_iszone(db));
909 	REQUIRE(nodep != NULL && *nodep == NULL);
910 
911 	if (db->methods->getoriginnode != NULL) {
912 		return ((db->methods->getoriginnode)(db, nodep));
913 	}
914 
915 	return (ISC_R_NOTFOUND);
916 }
917 
918 dns_stats_t *
919 dns_db_getrrsetstats(dns_db_t *db) {
920 	REQUIRE(DNS_DB_VALID(db));
921 
922 	if (db->methods->getrrsetstats != NULL) {
923 		return ((db->methods->getrrsetstats)(db));
924 	}
925 
926 	return (NULL);
927 }
928 
929 isc_result_t
930 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
931 	REQUIRE(DNS_DB_VALID(db));
932 
933 	if (db->methods->setcachestats != NULL) {
934 		return ((db->methods->setcachestats)(db, stats));
935 	}
936 
937 	return (ISC_R_NOTIMPLEMENTED);
938 }
939 
940 isc_result_t
941 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
942 			  dns_hash_t *hash, uint8_t *flags,
943 			  uint16_t *iterations, unsigned char *salt,
944 			  size_t *salt_length) {
945 	REQUIRE(DNS_DB_VALID(db));
946 	REQUIRE(dns_db_iszone(db));
947 
948 	if (db->methods->getnsec3parameters != NULL) {
949 		return ((db->methods->getnsec3parameters)(db, version, hash,
950 							  flags, iterations,
951 							  salt, salt_length));
952 	}
953 
954 	return (ISC_R_NOTFOUND);
955 }
956 
957 isc_result_t
958 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
959 	       uint64_t *bytes) {
960 	REQUIRE(DNS_DB_VALID(db));
961 	REQUIRE(dns_db_iszone(db));
962 
963 	if (db->methods->getsize != NULL) {
964 		return ((db->methods->getsize)(db, version, records, bytes));
965 	}
966 
967 	return (ISC_R_NOTFOUND);
968 }
969 
970 isc_result_t
971 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
972 		      isc_stdtime_t resign) {
973 	if (db->methods->setsigningtime != NULL) {
974 		return ((db->methods->setsigningtime)(db, rdataset, resign));
975 	}
976 	return (ISC_R_NOTIMPLEMENTED);
977 }
978 
979 isc_result_t
980 dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
981 		      dns_name_t *name) {
982 	if (db->methods->getsigningtime != NULL) {
983 		return ((db->methods->getsigningtime)(db, rdataset, name));
984 	}
985 	return (ISC_R_NOTFOUND);
986 }
987 
988 void
989 dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
990 		dns_dbversion_t *version) {
991 	if (db->methods->resigned != NULL) {
992 		(db->methods->resigned)(db, rdataset, version);
993 	}
994 }
995 
996 /*
997  * Attach a database to policy zone databases.
998  * This should only happen when the caller has already ensured that
999  * it is dealing with a database that understands response policy zones.
1000  */
1001 void
1002 dns_db_rpz_attach(dns_db_t *db, void *rpzs, uint8_t rpz_num) {
1003 	REQUIRE(db->methods->rpz_attach != NULL);
1004 	(db->methods->rpz_attach)(db, rpzs, rpz_num);
1005 }
1006 
1007 /*
1008  * Finish loading a response policy zone.
1009  */
1010 isc_result_t
1011 dns_db_rpz_ready(dns_db_t *db) {
1012 	if (db->methods->rpz_ready == NULL) {
1013 		return (ISC_R_SUCCESS);
1014 	}
1015 	return ((db->methods->rpz_ready)(db));
1016 }
1017 
1018 /**
1019  * Attach a notify-on-update function the database
1020  */
1021 isc_result_t
1022 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
1023 			     void *fn_arg) {
1024 	dns_dbonupdatelistener_t *listener;
1025 
1026 	REQUIRE(db != NULL);
1027 	REQUIRE(fn != NULL);
1028 
1029 	listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t));
1030 
1031 	listener->onupdate = fn;
1032 	listener->onupdate_arg = fn_arg;
1033 
1034 	ISC_LINK_INIT(listener, link);
1035 	ISC_LIST_APPEND(db->update_listeners, listener, link);
1036 
1037 	return (ISC_R_SUCCESS);
1038 }
1039 
1040 isc_result_t
1041 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
1042 			       void *fn_arg) {
1043 	dns_dbonupdatelistener_t *listener;
1044 
1045 	REQUIRE(db != NULL);
1046 
1047 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
1048 	     listener = ISC_LIST_NEXT(listener, link))
1049 	{
1050 		if ((listener->onupdate == fn) &&
1051 		    (listener->onupdate_arg == fn_arg)) {
1052 			ISC_LIST_UNLINK(db->update_listeners, listener, link);
1053 			isc_mem_put(db->mctx, listener,
1054 				    sizeof(dns_dbonupdatelistener_t));
1055 			return (ISC_R_SUCCESS);
1056 		}
1057 	}
1058 
1059 	return (ISC_R_NOTFOUND);
1060 }
1061 
1062 isc_result_t
1063 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
1064 	REQUIRE(db != NULL);
1065 	REQUIRE(node != NULL);
1066 	REQUIRE(name != NULL);
1067 
1068 	if (db->methods->nodefullname == NULL) {
1069 		return (ISC_R_NOTIMPLEMENTED);
1070 	}
1071 	return ((db->methods->nodefullname)(db, node, name));
1072 }
1073 
1074 isc_result_t
1075 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
1076 	REQUIRE(DNS_DB_VALID(db));
1077 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1078 
1079 	if (db->methods->setservestalettl != NULL) {
1080 		return ((db->methods->setservestalettl)(db, ttl));
1081 	}
1082 	return (ISC_R_NOTIMPLEMENTED);
1083 }
1084 
1085 isc_result_t
1086 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
1087 	REQUIRE(DNS_DB_VALID(db));
1088 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1089 
1090 	if (db->methods->getservestalettl != NULL) {
1091 		return ((db->methods->getservestalettl)(db, ttl));
1092 	}
1093 	return (ISC_R_NOTIMPLEMENTED);
1094 }
1095 
1096 isc_result_t
1097 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
1098 	REQUIRE(DNS_DB_VALID(db));
1099 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1100 
1101 	if (db->methods->setservestalerefresh != NULL) {
1102 		return ((db->methods->setservestalerefresh)(db, interval));
1103 	}
1104 	return (ISC_R_NOTIMPLEMENTED);
1105 }
1106 
1107 isc_result_t
1108 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
1109 	REQUIRE(DNS_DB_VALID(db));
1110 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1111 
1112 	if (db->methods->getservestalerefresh != NULL) {
1113 		return ((db->methods->getservestalerefresh)(db, interval));
1114 	}
1115 	return (ISC_R_NOTIMPLEMENTED);
1116 }
1117 
1118 isc_result_t
1119 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
1120 	REQUIRE(dns_db_iszone(db));
1121 	REQUIRE(stats != NULL);
1122 
1123 	if (db->methods->setgluecachestats != NULL) {
1124 		return ((db->methods->setgluecachestats)(db, stats));
1125 	}
1126 
1127 	return (ISC_R_NOTIMPLEMENTED);
1128 }
1129