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