1 /* $NetBSD: db.c,v 1.8 2022/09/23 12:15:29 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 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 * 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 688 dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 689 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) { 690 /* 691 * Make '*iteratorp' an rdataset iteratator for all rdatasets at 692 * 'node' in version 'version' of 'db'. 693 */ 694 695 REQUIRE(DNS_DB_VALID(db)); 696 REQUIRE(iteratorp != NULL && *iteratorp == NULL); 697 698 return ((db->methods->allrdatasets)(db, node, version, now, iteratorp)); 699 } 700 701 isc_result_t 702 dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 703 isc_stdtime_t now, dns_rdataset_t *rdataset, 704 unsigned int options, dns_rdataset_t *addedrdataset) { 705 /* 706 * Add 'rdataset' to 'node' in version 'version' of 'db'. 707 */ 708 709 REQUIRE(DNS_DB_VALID(db)); 710 REQUIRE(node != NULL); 711 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) || 712 ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL && 713 (options & DNS_DBADD_MERGE) == 0)); 714 REQUIRE((options & DNS_DBADD_EXACT) == 0 || 715 (options & DNS_DBADD_MERGE) != 0); 716 REQUIRE(DNS_RDATASET_VALID(rdataset)); 717 REQUIRE(dns_rdataset_isassociated(rdataset)); 718 REQUIRE(rdataset->rdclass == db->rdclass); 719 REQUIRE(addedrdataset == NULL || 720 (DNS_RDATASET_VALID(addedrdataset) && 721 !dns_rdataset_isassociated(addedrdataset))); 722 723 return ((db->methods->addrdataset)(db, node, version, now, rdataset, 724 options, addedrdataset)); 725 } 726 727 isc_result_t 728 dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, 729 dns_dbversion_t *version, dns_rdataset_t *rdataset, 730 unsigned int options, dns_rdataset_t *newrdataset) { 731 /* 732 * Remove any rdata in 'rdataset' from 'node' in version 'version' of 733 * 'db'. 734 */ 735 736 REQUIRE(DNS_DB_VALID(db)); 737 REQUIRE(node != NULL); 738 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL); 739 REQUIRE(DNS_RDATASET_VALID(rdataset)); 740 REQUIRE(dns_rdataset_isassociated(rdataset)); 741 REQUIRE(rdataset->rdclass == db->rdclass); 742 REQUIRE(newrdataset == NULL || 743 (DNS_RDATASET_VALID(newrdataset) && 744 !dns_rdataset_isassociated(newrdataset))); 745 746 return ((db->methods->subtractrdataset)(db, node, version, rdataset, 747 options, newrdataset)); 748 } 749 750 isc_result_t 751 dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, 752 dns_dbversion_t *version, dns_rdatatype_t type, 753 dns_rdatatype_t covers) { 754 /* 755 * Make it so that no rdataset of type 'type' exists at 'node' in 756 * version version 'version' of 'db'. 757 */ 758 759 REQUIRE(DNS_DB_VALID(db)); 760 REQUIRE(node != NULL); 761 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) || 762 ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL)); 763 764 return ((db->methods->deleterdataset)(db, node, version, type, covers)); 765 } 766 767 void 768 dns_db_overmem(dns_db_t *db, bool overmem) { 769 REQUIRE(DNS_DB_VALID(db)); 770 771 (db->methods->overmem)(db, overmem); 772 } 773 774 isc_result_t 775 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) { 776 isc_result_t result; 777 dns_dbnode_t *node = NULL; 778 dns_rdataset_t rdataset; 779 dns_rdata_t rdata = DNS_RDATA_INIT; 780 isc_buffer_t buffer; 781 782 REQUIRE(dns_db_iszone(db) || dns_db_isstub(db)); 783 784 result = dns_db_findnode(db, dns_db_origin(db), false, &node); 785 if (result != ISC_R_SUCCESS) { 786 return (result); 787 } 788 789 dns_rdataset_init(&rdataset); 790 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0, 791 (isc_stdtime_t)0, &rdataset, NULL); 792 if (result != ISC_R_SUCCESS) { 793 goto freenode; 794 } 795 796 result = dns_rdataset_first(&rdataset); 797 if (result != ISC_R_SUCCESS) { 798 goto freerdataset; 799 } 800 dns_rdataset_current(&rdataset, &rdata); 801 result = dns_rdataset_next(&rdataset); 802 INSIST(result == ISC_R_NOMORE); 803 804 INSIST(rdata.length > 20); 805 isc_buffer_init(&buffer, rdata.data, rdata.length); 806 isc_buffer_add(&buffer, rdata.length); 807 isc_buffer_forward(&buffer, rdata.length - 20); 808 *serialp = isc_buffer_getuint32(&buffer); 809 810 result = ISC_R_SUCCESS; 811 812 freerdataset: 813 dns_rdataset_disassociate(&rdataset); 814 815 freenode: 816 dns_db_detachnode(db, &node); 817 return (result); 818 } 819 820 unsigned int 821 dns_db_nodecount(dns_db_t *db) { 822 REQUIRE(DNS_DB_VALID(db)); 823 824 return ((db->methods->nodecount)(db)); 825 } 826 827 size_t 828 dns_db_hashsize(dns_db_t *db) { 829 REQUIRE(DNS_DB_VALID(db)); 830 831 if (db->methods->hashsize == NULL) { 832 return (0); 833 } 834 835 return ((db->methods->hashsize)(db)); 836 } 837 838 isc_result_t 839 dns_db_adjusthashsize(dns_db_t *db, size_t size) { 840 REQUIRE(DNS_DB_VALID(db)); 841 842 if (db->methods->adjusthashsize != NULL) { 843 return ((db->methods->adjusthashsize)(db, size)); 844 } 845 846 return (ISC_R_NOTIMPLEMENTED); 847 } 848 849 void 850 dns_db_settask(dns_db_t *db, isc_task_t *task) { 851 REQUIRE(DNS_DB_VALID(db)); 852 853 (db->methods->settask)(db, task); 854 } 855 856 isc_result_t 857 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, 858 isc_mem_t *mctx, dns_dbimplementation_t **dbimp) { 859 dns_dbimplementation_t *imp; 860 861 REQUIRE(name != NULL); 862 REQUIRE(dbimp != NULL && *dbimp == NULL); 863 864 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); 865 866 RWLOCK(&implock, isc_rwlocktype_write); 867 imp = impfind(name); 868 if (imp != NULL) { 869 RWUNLOCK(&implock, isc_rwlocktype_write); 870 return (ISC_R_EXISTS); 871 } 872 873 imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t)); 874 imp->name = name; 875 imp->create = create; 876 imp->mctx = NULL; 877 imp->driverarg = driverarg; 878 isc_mem_attach(mctx, &imp->mctx); 879 ISC_LINK_INIT(imp, link); 880 ISC_LIST_APPEND(implementations, imp, link); 881 RWUNLOCK(&implock, isc_rwlocktype_write); 882 883 *dbimp = imp; 884 885 return (ISC_R_SUCCESS); 886 } 887 888 void 889 dns_db_unregister(dns_dbimplementation_t **dbimp) { 890 dns_dbimplementation_t *imp; 891 892 REQUIRE(dbimp != NULL && *dbimp != NULL); 893 894 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); 895 896 imp = *dbimp; 897 *dbimp = NULL; 898 RWLOCK(&implock, isc_rwlocktype_write); 899 ISC_LIST_UNLINK(implementations, imp, link); 900 isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t)); 901 RWUNLOCK(&implock, isc_rwlocktype_write); 902 ENSURE(*dbimp == NULL); 903 } 904 905 isc_result_t 906 dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { 907 REQUIRE(DNS_DB_VALID(db)); 908 REQUIRE(dns_db_iszone(db)); 909 REQUIRE(nodep != NULL && *nodep == NULL); 910 911 if (db->methods->getoriginnode != NULL) { 912 return ((db->methods->getoriginnode)(db, nodep)); 913 } 914 915 return (ISC_R_NOTFOUND); 916 } 917 918 dns_stats_t * 919 dns_db_getrrsetstats(dns_db_t *db) { 920 REQUIRE(DNS_DB_VALID(db)); 921 922 if (db->methods->getrrsetstats != NULL) { 923 return ((db->methods->getrrsetstats)(db)); 924 } 925 926 return (NULL); 927 } 928 929 isc_result_t 930 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) { 931 REQUIRE(DNS_DB_VALID(db)); 932 933 if (db->methods->setcachestats != NULL) { 934 return ((db->methods->setcachestats)(db, stats)); 935 } 936 937 return (ISC_R_NOTIMPLEMENTED); 938 } 939 940 isc_result_t 941 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, 942 dns_hash_t *hash, uint8_t *flags, 943 uint16_t *iterations, unsigned char *salt, 944 size_t *salt_length) { 945 REQUIRE(DNS_DB_VALID(db)); 946 REQUIRE(dns_db_iszone(db)); 947 948 if (db->methods->getnsec3parameters != NULL) { 949 return ((db->methods->getnsec3parameters)(db, version, hash, 950 flags, iterations, 951 salt, salt_length)); 952 } 953 954 return (ISC_R_NOTFOUND); 955 } 956 957 isc_result_t 958 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records, 959 uint64_t *bytes) { 960 REQUIRE(DNS_DB_VALID(db)); 961 REQUIRE(dns_db_iszone(db)); 962 963 if (db->methods->getsize != NULL) { 964 return ((db->methods->getsize)(db, version, records, bytes)); 965 } 966 967 return (ISC_R_NOTFOUND); 968 } 969 970 isc_result_t 971 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, 972 isc_stdtime_t resign) { 973 if (db->methods->setsigningtime != NULL) { 974 return ((db->methods->setsigningtime)(db, rdataset, resign)); 975 } 976 return (ISC_R_NOTIMPLEMENTED); 977 } 978 979 isc_result_t 980 dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, 981 dns_name_t *name) { 982 if (db->methods->getsigningtime != NULL) { 983 return ((db->methods->getsigningtime)(db, rdataset, name)); 984 } 985 return (ISC_R_NOTFOUND); 986 } 987 988 void 989 dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, 990 dns_dbversion_t *version) { 991 if (db->methods->resigned != NULL) { 992 (db->methods->resigned)(db, rdataset, version); 993 } 994 } 995 996 /* 997 * Attach a database to policy zone databases. 998 * This should only happen when the caller has already ensured that 999 * it is dealing with a database that understands response policy zones. 1000 */ 1001 void 1002 dns_db_rpz_attach(dns_db_t *db, void *rpzs, uint8_t rpz_num) { 1003 REQUIRE(db->methods->rpz_attach != NULL); 1004 (db->methods->rpz_attach)(db, rpzs, rpz_num); 1005 } 1006 1007 /* 1008 * Finish loading a response policy zone. 1009 */ 1010 isc_result_t 1011 dns_db_rpz_ready(dns_db_t *db) { 1012 if (db->methods->rpz_ready == NULL) { 1013 return (ISC_R_SUCCESS); 1014 } 1015 return ((db->methods->rpz_ready)(db)); 1016 } 1017 1018 /** 1019 * Attach a notify-on-update function the database 1020 */ 1021 isc_result_t 1022 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn, 1023 void *fn_arg) { 1024 dns_dbonupdatelistener_t *listener; 1025 1026 REQUIRE(db != NULL); 1027 REQUIRE(fn != NULL); 1028 1029 listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t)); 1030 1031 listener->onupdate = fn; 1032 listener->onupdate_arg = fn_arg; 1033 1034 ISC_LINK_INIT(listener, link); 1035 ISC_LIST_APPEND(db->update_listeners, listener, link); 1036 1037 return (ISC_R_SUCCESS); 1038 } 1039 1040 isc_result_t 1041 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn, 1042 void *fn_arg) { 1043 dns_dbonupdatelistener_t *listener; 1044 1045 REQUIRE(db != NULL); 1046 1047 for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL; 1048 listener = ISC_LIST_NEXT(listener, link)) 1049 { 1050 if ((listener->onupdate == fn) && 1051 (listener->onupdate_arg == fn_arg)) { 1052 ISC_LIST_UNLINK(db->update_listeners, listener, link); 1053 isc_mem_put(db->mctx, listener, 1054 sizeof(dns_dbonupdatelistener_t)); 1055 return (ISC_R_SUCCESS); 1056 } 1057 } 1058 1059 return (ISC_R_NOTFOUND); 1060 } 1061 1062 isc_result_t 1063 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { 1064 REQUIRE(db != NULL); 1065 REQUIRE(node != NULL); 1066 REQUIRE(name != NULL); 1067 1068 if (db->methods->nodefullname == NULL) { 1069 return (ISC_R_NOTIMPLEMENTED); 1070 } 1071 return ((db->methods->nodefullname)(db, node, name)); 1072 } 1073 1074 isc_result_t 1075 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) { 1076 REQUIRE(DNS_DB_VALID(db)); 1077 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1078 1079 if (db->methods->setservestalettl != NULL) { 1080 return ((db->methods->setservestalettl)(db, ttl)); 1081 } 1082 return (ISC_R_NOTIMPLEMENTED); 1083 } 1084 1085 isc_result_t 1086 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) { 1087 REQUIRE(DNS_DB_VALID(db)); 1088 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1089 1090 if (db->methods->getservestalettl != NULL) { 1091 return ((db->methods->getservestalettl)(db, ttl)); 1092 } 1093 return (ISC_R_NOTIMPLEMENTED); 1094 } 1095 1096 isc_result_t 1097 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) { 1098 REQUIRE(DNS_DB_VALID(db)); 1099 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1100 1101 if (db->methods->setservestalerefresh != NULL) { 1102 return ((db->methods->setservestalerefresh)(db, interval)); 1103 } 1104 return (ISC_R_NOTIMPLEMENTED); 1105 } 1106 1107 isc_result_t 1108 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) { 1109 REQUIRE(DNS_DB_VALID(db)); 1110 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1111 1112 if (db->methods->getservestalerefresh != NULL) { 1113 return ((db->methods->getservestalerefresh)(db, interval)); 1114 } 1115 return (ISC_R_NOTIMPLEMENTED); 1116 } 1117 1118 isc_result_t 1119 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) { 1120 REQUIRE(dns_db_iszone(db)); 1121 REQUIRE(stats != NULL); 1122 1123 if (db->methods->setgluecachestats != NULL) { 1124 return ((db->methods->setgluecachestats)(db, stats)); 1125 } 1126 1127 return (ISC_R_NOTIMPLEMENTED); 1128 } 1129