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