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