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
initialize(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 *
impfind(const char * name)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
dns_db_create(isc_mem_t * mctx,const char * db_type,dns_name_t * origin,dns_dbtype_t type,dns_rdataclass_t rdclass,unsigned int argc,char * argv[],dns_db_t ** dbp)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
dns_db_attach(dns_db_t * source,dns_db_t ** targetp)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
dns_db_detach(dns_db_t ** dbp)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
dns_db_ondestroy(dns_db_t * db,isc_task_t * task,isc_event_t ** eventp)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
dns_db_iscache(dns_db_t * db)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
dns_db_iszone(dns_db_t * db)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
dns_db_isstub(dns_db_t * db)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
dns_db_isdnssec(dns_db_t * db)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
dns_db_issecure(dns_db_t * db)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
dns_db_ispersistent(dns_db_t * db)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 *
dns_db_origin(dns_db_t * db)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
dns_db_class(dns_db_t * db)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
dns_db_beginload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)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
dns_db_endload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)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
dns_db_load(dns_db_t * db,const char * filename)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
dns_db_load2(dns_db_t * db,const char * filename,dns_masterformat_t format)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
dns_db_load3(dns_db_t * db,const char * filename,dns_masterformat_t format,unsigned int options)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
dns_db_serialize(dns_db_t * db,dns_dbversion_t * version,FILE * file)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
dns_db_dump(dns_db_t * db,dns_dbversion_t * version,const char * filename)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
dns_db_dump2(dns_db_t * db,dns_dbversion_t * version,const char * filename,dns_masterformat_t masterformat)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
dns_db_currentversion(dns_db_t * db,dns_dbversion_t ** versionp)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
dns_db_newversion(dns_db_t * db,dns_dbversion_t ** versionp)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
dns_db_attachversion(dns_db_t * db,dns_dbversion_t * source,dns_dbversion_t ** targetp)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
dns_db_closeversion(dns_db_t * db,dns_dbversion_t ** versionp,isc_boolean_t commit)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
dns_db_findnode(dns_db_t * db,dns_name_t * name,isc_boolean_t create,dns_dbnode_t ** nodep)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
dns_db_findnodeext(dns_db_t * db,dns_name_t * name,isc_boolean_t create,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_dbnode_t ** nodep)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
dns_db_findnsec3node(dns_db_t * db,dns_name_t * name,isc_boolean_t create,dns_dbnode_t ** nodep)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
dns_db_find(dns_db_t * db,dns_name_t * name,dns_dbversion_t * version,dns_rdatatype_t type,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
dns_db_findext(dns_db_t * db,dns_name_t * name,dns_dbversion_t * version,dns_rdatatype_t type,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
dns_db_findzonecut(dns_db_t * db,dns_name_t * name,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
dns_db_attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)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
dns_db_detachnode(dns_db_t * db,dns_dbnode_t ** nodep)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
dns_db_transfernode(dns_db_t * db,dns_dbnode_t ** sourcep,dns_dbnode_t ** targetp)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
dns_db_expirenode(dns_db_t * db,dns_dbnode_t * node,isc_stdtime_t now)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
dns_db_printnode(dns_db_t * db,dns_dbnode_t * node,FILE * out)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
dns_db_createiterator(dns_db_t * db,unsigned int flags,dns_dbiterator_t ** iteratorp)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
dns_db_findrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers,isc_stdtime_t now,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
dns_db_allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)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
dns_db_addrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * addedrdataset)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
dns_db_subtractrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * newrdataset)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
dns_db_deleterdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers)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
dns_db_overmem(dns_db_t * db,isc_boolean_t overmem)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
dns_db_getsoaserial(dns_db_t * db,dns_dbversion_t * ver,isc_uint32_t * serialp)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
dns_db_nodecount(dns_db_t * db)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
dns_db_hashsize(dns_db_t * db)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
dns_db_settask(dns_db_t * db,isc_task_t * task)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
dns_db_register(const char * name,dns_dbcreatefunc_t create,void * driverarg,isc_mem_t * mctx,dns_dbimplementation_t ** dbimp)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
dns_db_unregister(dns_dbimplementation_t ** dbimp)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
dns_db_getoriginnode(dns_db_t * db,dns_dbnode_t ** nodep)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 *
dns_db_getrrsetstats(dns_db_t * db)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
dns_db_setcachestats(dns_db_t * db,isc_stats_t * stats)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
dns_db_getnsec3parameters(dns_db_t * db,dns_dbversion_t * version,dns_hash_t * hash,isc_uint8_t * flags,isc_uint16_t * iterations,unsigned char * salt,size_t * salt_length)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
dns_db_setsigningtime(dns_db_t * db,dns_rdataset_t * rdataset,isc_stdtime_t resign)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
dns_db_getsigningtime(dns_db_t * db,dns_rdataset_t * rdataset,dns_name_t * name)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
dns_db_resigned(dns_db_t * db,dns_rdataset_t * rdataset,dns_dbversion_t * version)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
dns_db_rpz_attach(dns_db_t * db,dns_rpz_zones_t * rpzs,dns_rpz_num_t rpz_num)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
dns_db_rpz_ready(dns_db_t * db)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