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