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