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