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