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 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 unsigned int dns_pps = 0U; 66 67 static ISC_LIST(dns_dbimplementation_t) implementations; 68 static isc_rwlock_t implock; 69 static isc_once_t once = ISC_ONCE_INIT; 70 71 static dns_dbimplementation_t rbtimp; 72 73 static void 74 initialize(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 87 static dns_dbimplementation_t * 88 impfind(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 105 isc_result_t 106 dns_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 138 void 139 dns_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 152 void 153 dns_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 166 bool 167 dns_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 181 bool 182 dns_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 196 bool 197 dns_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 211 bool 212 dns_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 226 bool 227 dns_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 238 bool 239 dns_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 249 dns_name_t * 250 dns_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 260 dns_rdataclass_t 261 dns_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 271 isc_result_t 272 dns_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 283 isc_result_t 284 dns_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 304 isc_result_t 305 dns_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 343 isc_result_t 344 dns_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 353 void 354 dns_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 366 isc_result_t 367 dns_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 379 void 380 dns_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 396 void 397 dns_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 425 isc_result_t 426 dns_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 443 isc_result_t 444 dns_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 463 isc_result_t 464 dns_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 476 isc_result_t 477 dns_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 507 isc_result_t 508 dns_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 539 isc_result_t 540 dns_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 563 void 564 dns_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 576 void 577 dns_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 590 void 591 dns_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 614 isc_result_t 615 dns_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 627 void 628 dns_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 644 isc_result_t 645 dns_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 661 isc_result_t 662 dns_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 680 isc_result_t 681 dns_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 696 isc_result_t 697 dns_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 722 isc_result_t 723 dns_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 745 isc_result_t 746 dns_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 762 void 763 dns_db_overmem(dns_db_t *db, bool overmem) { 764 REQUIRE(DNS_DB_VALID(db)); 765 766 (db->methods->overmem)(db, overmem); 767 } 768 769 isc_result_t 770 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, 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 807 freerdataset: 808 dns_rdataset_disassociate(&rdataset); 809 810 freenode: 811 dns_db_detachnode(db, &node); 812 return (result); 813 } 814 815 unsigned int 816 dns_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 822 size_t 823 dns_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 833 void 834 dns_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 840 isc_result_t 841 dns_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 872 void 873 dns_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 889 isc_result_t 890 dns_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 902 dns_stats_t * 903 dns_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 913 isc_result_t 914 dns_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 924 isc_result_t 925 dns_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 941 isc_result_t 942 dns_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 954 isc_result_t 955 dns_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 963 isc_result_t 964 dns_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 972 void 973 dns_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 */ 985 void 986 dns_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 */ 994 isc_result_t 995 dns_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 */ 1005 isc_result_t 1006 dns_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 1034 isc_result_t 1035 dns_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 1057 isc_result_t 1058 dns_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 1069 isc_result_t 1070 dns_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 1080 isc_result_t 1081 dns_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 1091 isc_result_t 1092 dns_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 1102 isc_result_t 1103 dns_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 1113 isc_result_t 1114 dns_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