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