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