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