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