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