1 /* $NetBSD: db.c,v 1.15 2026/05/20 16:53:45 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 #include <dns/rdataslab.h> 47 #include <dns/stats.h> 48 49 /*** 50 *** Private Types 51 ***/ 52 53 struct dns_dbimplementation { 54 const char *name; 55 dns_dbcreatefunc_t create; 56 isc_mem_t *mctx; 57 void *driverarg; 58 ISC_LINK(dns_dbimplementation_t) link; 59 }; 60 61 /*** 62 *** Supported DB Implementations Registry 63 ***/ 64 65 /* 66 * Built in database implementations are registered here. 67 */ 68 69 #include "db_p.h" 70 #include "qpcache_p.h" 71 #include "qpzone_p.h" 72 #include "rbtdb_p.h" 73 74 unsigned int dns_pps = 0U; 75 76 static ISC_LIST(dns_dbimplementation_t) implementations; 77 static isc_rwlock_t implock; 78 static isc_once_t once = ISC_ONCE_INIT; 79 80 static dns_dbimplementation_t rbtimp; 81 static dns_dbimplementation_t qpimp; 82 static dns_dbimplementation_t qpzoneimp; 83 84 static void 85 initialize(void) { 86 isc_rwlock_init(&implock); 87 88 ISC_LIST_INIT(implementations); 89 90 rbtimp = (dns_dbimplementation_t){ 91 .name = "rbt", 92 .create = dns__rbtdb_create, 93 .link = ISC_LINK_INITIALIZER, 94 }; 95 96 qpimp = (dns_dbimplementation_t){ 97 .name = "qpcache", 98 .create = dns__qpcache_create, 99 .link = ISC_LINK_INITIALIZER, 100 }; 101 102 qpzoneimp = (dns_dbimplementation_t){ 103 .name = "qpzone", 104 .create = dns__qpzone_create, 105 .link = ISC_LINK_INITIALIZER, 106 }; 107 108 ISC_LIST_APPEND(implementations, &rbtimp, link); 109 ISC_LIST_APPEND(implementations, &qpimp, link); 110 ISC_LIST_APPEND(implementations, &qpzoneimp, link); 111 } 112 113 static dns_dbimplementation_t * 114 impfind(const char *name) { 115 dns_dbimplementation_t *imp; 116 117 for (imp = ISC_LIST_HEAD(implementations); imp != NULL; 118 imp = ISC_LIST_NEXT(imp, link)) 119 { 120 if (strcasecmp(name, imp->name) == 0) { 121 return imp; 122 } 123 } 124 return NULL; 125 } 126 127 static void 128 call_updatenotify(dns_db_t *db); 129 130 /*** 131 *** Basic DB Methods 132 ***/ 133 134 isc_result_t 135 dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin, 136 dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc, 137 char *argv[], dns_db_t **dbp) { 138 dns_dbimplementation_t *impinfo = NULL; 139 140 isc_once_do(&once, initialize); 141 142 /* 143 * Create a new database using implementation 'db_type'. 144 */ 145 146 REQUIRE(dbp != NULL && *dbp == NULL); 147 REQUIRE(dns_name_isabsolute(origin)); 148 149 RWLOCK(&implock, isc_rwlocktype_read); 150 impinfo = impfind(db_type); 151 if (impinfo != NULL) { 152 isc_result_t result; 153 result = ((impinfo->create)(mctx, origin, type, rdclass, argc, 154 argv, impinfo->driverarg, dbp)); 155 RWUNLOCK(&implock, isc_rwlocktype_read); 156 157 #if DNS_DB_TRACE 158 fprintf(stderr, "dns_db_create:%s:%s:%d:%p->references = 1\n", 159 __func__, __FILE__, __LINE__ + 1, *dbp); 160 #endif 161 return result; 162 } 163 164 RWUNLOCK(&implock, isc_rwlocktype_read); 165 166 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB, 167 ISC_LOG_ERROR, "unsupported database type '%s'", db_type); 168 169 return ISC_R_NOTFOUND; 170 } 171 172 static void 173 dns__db_destroy(dns_db_t *db) { 174 (db->methods->destroy)(db); 175 } 176 177 #if DNS_DB_TRACE 178 ISC_REFCOUNT_TRACE_IMPL(dns_db, dns__db_destroy); 179 #else 180 ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy); 181 #endif 182 183 bool 184 dns_db_iscache(dns_db_t *db) { 185 /* 186 * Does 'db' have cache semantics? 187 */ 188 189 REQUIRE(DNS_DB_VALID(db)); 190 191 if ((db->attributes & DNS_DBATTR_CACHE) != 0) { 192 return true; 193 } 194 195 return false; 196 } 197 198 bool 199 dns_db_iszone(dns_db_t *db) { 200 /* 201 * Does 'db' have zone semantics? 202 */ 203 204 REQUIRE(DNS_DB_VALID(db)); 205 206 if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) { 207 return true; 208 } 209 210 return false; 211 } 212 213 bool 214 dns_db_isstub(dns_db_t *db) { 215 /* 216 * Does 'db' have stub semantics? 217 */ 218 219 REQUIRE(DNS_DB_VALID(db)); 220 221 if ((db->attributes & DNS_DBATTR_STUB) != 0) { 222 return true; 223 } 224 225 return false; 226 } 227 228 bool 229 dns_db_issecure(dns_db_t *db) { 230 /* 231 * Is 'db' secure? 232 */ 233 234 REQUIRE(DNS_DB_VALID(db)); 235 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 236 237 if (db->methods->issecure != NULL) { 238 return (db->methods->issecure)(db); 239 } 240 return false; 241 } 242 243 bool 244 dns_db_ispersistent(dns_db_t *db) { 245 /* 246 * Is 'db' persistent? 247 */ 248 249 REQUIRE(DNS_DB_VALID(db)); 250 251 if (db->methods->beginload == NULL) { 252 /* If the database can't be loaded, assume it's persistent */ 253 return true; 254 } 255 256 return false; 257 } 258 259 dns_name_t * 260 dns_db_origin(dns_db_t *db) { 261 /* 262 * The origin of the database. 263 */ 264 265 REQUIRE(DNS_DB_VALID(db)); 266 267 return &db->origin; 268 } 269 270 dns_rdataclass_t 271 dns_db_class(dns_db_t *db) { 272 /* 273 * The class of the database. 274 */ 275 276 REQUIRE(DNS_DB_VALID(db)); 277 278 return db->rdclass; 279 } 280 281 isc_result_t 282 dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 283 /* 284 * Begin loading 'db'. 285 */ 286 287 REQUIRE(DNS_DB_VALID(db)); 288 REQUIRE(DNS_CALLBACK_VALID(callbacks)); 289 290 if (db->methods->beginload != NULL) { 291 return (db->methods->beginload)(db, callbacks); 292 } 293 return ISC_R_NOTIMPLEMENTED; 294 } 295 296 isc_result_t 297 dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 298 /* 299 * Finish loading 'db'. 300 */ 301 302 REQUIRE(DNS_DB_VALID(db)); 303 REQUIRE(DNS_CALLBACK_VALID(callbacks)); 304 REQUIRE(callbacks->add_private != NULL); 305 306 /* 307 * When dns_db_endload() is called, we call the onupdate function 308 * for all registered listeners, regardless of whether the underlying 309 * database has an 'endload' implementation. 310 */ 311 call_updatenotify(db); 312 313 if (db->methods->endload != NULL) { 314 return (db->methods->endload)(db, callbacks); 315 } 316 317 return ISC_R_NOTIMPLEMENTED; 318 } 319 320 isc_result_t 321 dns_db_beginupdate(dns_db_t *db, dns_dbversion_t *ver, 322 dns_rdatacallbacks_t *callbacks) { 323 /* 324 * Begin updating 'db'. 325 */ 326 327 REQUIRE(DNS_DB_VALID(db)); 328 REQUIRE(dns_db_iszone(db)); 329 REQUIRE(DNS_CALLBACK_VALID(callbacks)); 330 331 if (db->methods->beginupdate != NULL) { 332 return (db->methods->beginupdate)(db, ver, callbacks); 333 } 334 return ISC_R_NOTIMPLEMENTED; 335 } 336 337 isc_result_t 338 dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 339 /* 340 * Commit the update to 'db'. 341 */ 342 343 REQUIRE(DNS_DB_VALID(db)); 344 REQUIRE(dns_db_iszone(db)); 345 REQUIRE(DNS_CALLBACK_VALID(callbacks)); 346 347 if (db->methods->commitupdate != NULL) { 348 return (db->methods->commitupdate)(db, callbacks); 349 } 350 351 return ISC_R_NOTIMPLEMENTED; 352 } 353 354 isc_result_t 355 dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { 356 /* 357 * Abort the update to 'db'. 358 */ 359 360 REQUIRE(DNS_DB_VALID(db)); 361 REQUIRE(dns_db_iszone(db)); 362 REQUIRE(DNS_CALLBACK_VALID(callbacks)); 363 364 if (db->methods->abortupdate != NULL) { 365 return (db->methods->abortupdate)(db, callbacks); 366 } 367 368 return ISC_R_NOTIMPLEMENTED; 369 } 370 371 isc_result_t 372 dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format, 373 unsigned int options) { 374 isc_result_t result, eresult; 375 dns_rdatacallbacks_t callbacks; 376 377 /* 378 * Load master file 'filename' into 'db'. 379 */ 380 381 REQUIRE(DNS_DB_VALID(db)); 382 383 if ((db->attributes & DNS_DBATTR_CACHE) != 0) { 384 options |= DNS_MASTER_AGETTL; 385 } 386 387 dns_rdatacallbacks_init(&callbacks); 388 result = dns_db_beginload(db, &callbacks); 389 if (result != ISC_R_SUCCESS) { 390 return result; 391 } 392 result = dns_master_loadfile(filename, &db->origin, &db->origin, 393 db->rdclass, options, 0, &callbacks, NULL, 394 NULL, db->mctx, format, 0); 395 eresult = dns_db_endload(db, &callbacks); 396 /* 397 * We always call dns_db_endload(), but we only want to return its 398 * result if dns_master_loadfile() succeeded. If dns_master_loadfile() 399 * failed, we want to return the result code it gave us. 400 */ 401 if (eresult != ISC_R_SUCCESS && 402 (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)) 403 { 404 result = eresult; 405 } 406 407 return result; 408 } 409 410 /*** 411 *** Version Methods 412 ***/ 413 414 void 415 dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) { 416 /* 417 * Open the current version for reading. 418 */ 419 420 REQUIRE(DNS_DB_VALID(db)); 421 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 422 REQUIRE(versionp != NULL && *versionp == NULL); 423 424 (db->methods->currentversion)(db, versionp); 425 } 426 427 isc_result_t 428 dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) { 429 /* 430 * Open a new version for reading and writing. 431 */ 432 433 REQUIRE(DNS_DB_VALID(db)); 434 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 435 REQUIRE(versionp != NULL && *versionp == NULL); 436 437 if (db->methods->newversion != NULL) { 438 return (db->methods->newversion)(db, versionp); 439 } 440 return ISC_R_NOTIMPLEMENTED; 441 } 442 443 void 444 dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source, 445 dns_dbversion_t **targetp) { 446 /* 447 * Attach '*targetp' to 'source'. 448 */ 449 450 REQUIRE(DNS_DB_VALID(db)); 451 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 452 REQUIRE(source != NULL); 453 REQUIRE(targetp != NULL && *targetp == NULL); 454 455 (db->methods->attachversion)(db, source, targetp); 456 457 ENSURE(*targetp != NULL); 458 } 459 460 void 461 dns__db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, 462 bool commit DNS__DB_FLARG) { 463 /* 464 * Close version '*versionp'. 465 */ 466 467 REQUIRE(DNS_DB_VALID(db)); 468 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 469 REQUIRE(versionp != NULL && *versionp != NULL); 470 471 (db->methods->closeversion)(db, versionp, commit DNS__DB_FLARG_PASS); 472 473 if (commit) { 474 call_updatenotify(db); 475 } 476 477 ENSURE(*versionp == NULL); 478 } 479 480 /*** 481 *** Node Methods 482 ***/ 483 484 isc_result_t 485 dns__db_findnode(dns_db_t *db, const dns_name_t *name, bool create, 486 dns_dbnode_t **nodep DNS__DB_FLARG) { 487 /* 488 * Find the node with name 'name'. 489 */ 490 491 REQUIRE(DNS_DB_VALID(db)); 492 REQUIRE(nodep != NULL && *nodep == NULL); 493 494 if (db->methods->findnode != NULL) { 495 return (db->methods->findnode)(db, name, create, 496 nodep DNS__DB_FLARG_PASS); 497 } else { 498 return (db->methods->findnodeext)(db, name, create, NULL, NULL, 499 nodep DNS__DB_FLARG_PASS); 500 } 501 } 502 503 isc_result_t 504 dns__db_findnodeext(dns_db_t *db, const dns_name_t *name, bool create, 505 dns_clientinfomethods_t *methods, 506 dns_clientinfo_t *clientinfo, 507 dns_dbnode_t **nodep DNS__DB_FLARG) { 508 /* 509 * Find the node with name 'name', passing 'arg' to the database 510 * implementation. 511 */ 512 513 REQUIRE(DNS_DB_VALID(db)); 514 REQUIRE(nodep != NULL && *nodep == NULL); 515 516 if (db->methods->findnodeext != NULL) { 517 return (db->methods->findnodeext)(db, name, create, methods, 518 clientinfo, 519 nodep DNS__DB_FLARG_PASS); 520 } else { 521 return (db->methods->findnode)(db, name, create, 522 nodep DNS__DB_FLARG_PASS); 523 } 524 } 525 526 isc_result_t 527 dns__db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, 528 dns_dbnode_t **nodep DNS__DB_FLARG) { 529 /* 530 * Find the node with name 'name'. 531 */ 532 533 REQUIRE(DNS_DB_VALID(db)); 534 REQUIRE(nodep != NULL && *nodep == NULL); 535 536 return (db->methods->findnsec3node)(db, name, create, 537 nodep DNS__DB_FLARG_PASS); 538 } 539 540 isc_result_t 541 dns__db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, 542 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 543 dns_dbnode_t **nodep, dns_name_t *foundname, 544 dns_rdataset_t *rdataset, 545 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 546 /* 547 * Find the best match for 'name' and 'type' in version 'version' 548 * of 'db'. 549 */ 550 551 REQUIRE(DNS_DB_VALID(db)); 552 REQUIRE(type != dns_rdatatype_rrsig); 553 REQUIRE(nodep == NULL || *nodep == NULL); 554 REQUIRE(dns_name_hasbuffer(foundname)); 555 REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) && 556 !dns_rdataset_isassociated(rdataset))); 557 REQUIRE(sigrdataset == NULL || 558 (DNS_RDATASET_VALID(sigrdataset) && 559 !dns_rdataset_isassociated(sigrdataset))); 560 561 if (db->methods->find != NULL) { 562 return (db->methods->find)(db, name, version, type, options, 563 now, nodep, foundname, rdataset, 564 sigrdataset DNS__DB_FLARG_PASS); 565 } else { 566 return (db->methods->findext)( 567 db, name, version, type, options, now, nodep, foundname, 568 NULL, NULL, rdataset, sigrdataset DNS__DB_FLARG_PASS); 569 } 570 } 571 572 isc_result_t 573 dns__db_findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, 574 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 575 dns_dbnode_t **nodep, dns_name_t *foundname, 576 dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo, 577 dns_rdataset_t *rdataset, 578 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 579 /* 580 * Find the best match for 'name' and 'type' in version 'version' 581 * of 'db', passing in 'arg'. 582 */ 583 584 REQUIRE(DNS_DB_VALID(db)); 585 REQUIRE(type != dns_rdatatype_rrsig); 586 REQUIRE(nodep == NULL || *nodep == NULL); 587 REQUIRE(dns_name_hasbuffer(foundname)); 588 REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) && 589 !dns_rdataset_isassociated(rdataset))); 590 REQUIRE(sigrdataset == NULL || 591 (DNS_RDATASET_VALID(sigrdataset) && 592 !dns_rdataset_isassociated(sigrdataset))); 593 594 if (db->methods->findext != NULL) { 595 return (db->methods->findext)(db, name, version, type, options, 596 now, nodep, foundname, methods, 597 clientinfo, rdataset, 598 sigrdataset DNS__DB_FLARG_PASS); 599 } else { 600 return (db->methods->find)(db, name, version, type, options, 601 now, nodep, foundname, rdataset, 602 sigrdataset DNS__DB_FLARG_PASS); 603 } 604 } 605 606 isc_result_t 607 dns__db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, 608 isc_stdtime_t now, dns_dbnode_t **nodep, 609 dns_name_t *foundname, dns_name_t *dcname, 610 dns_rdataset_t *rdataset, 611 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 612 /* 613 * Find the deepest known zonecut which encloses 'name' in 'db'. 614 * foundname is the zonecut, dcname is the deepest name we have 615 * in database that is part of queried name. 616 */ 617 618 REQUIRE(DNS_DB_VALID(db)); 619 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 620 REQUIRE(nodep == NULL || *nodep == NULL); 621 REQUIRE(dns_name_hasbuffer(foundname)); 622 REQUIRE(sigrdataset == NULL || 623 (DNS_RDATASET_VALID(sigrdataset) && 624 !dns_rdataset_isassociated(sigrdataset))); 625 626 if (db->methods->findzonecut != NULL) { 627 return (db->methods->findzonecut)( 628 db, name, options, now, nodep, foundname, dcname, 629 rdataset, sigrdataset DNS__DB_FLARG_PASS); 630 } 631 return ISC_R_NOTIMPLEMENTED; 632 } 633 634 void 635 dns__db_attachnode(dns_db_t *db, dns_dbnode_t *source, 636 dns_dbnode_t **targetp DNS__DB_FLARG) { 637 /* 638 * Attach *targetp to source. 639 */ 640 641 REQUIRE(DNS_DB_VALID(db)); 642 REQUIRE(source != NULL); 643 REQUIRE(targetp != NULL && *targetp == NULL); 644 645 (db->methods->attachnode)(db, source, targetp DNS__DB_FLARG_PASS); 646 } 647 648 void 649 dns__db_detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 650 /* 651 * Detach *nodep from its node. 652 */ 653 654 REQUIRE(DNS_DB_VALID(db)); 655 REQUIRE(nodep != NULL && *nodep != NULL); 656 657 (db->methods->detachnode)(db, nodep DNS__DB_FLARG_PASS); 658 659 ENSURE(*nodep == NULL); 660 } 661 662 void 663 dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep, 664 dns_dbnode_t **targetp) { 665 REQUIRE(DNS_DB_VALID(db)); 666 REQUIRE(targetp != NULL && *targetp == NULL); 667 REQUIRE(sourcep != NULL && *sourcep != NULL); 668 669 *targetp = *sourcep; 670 *sourcep = NULL; 671 } 672 673 /*** 674 *** DB Iterator Creation 675 ***/ 676 677 isc_result_t 678 dns_db_createiterator(dns_db_t *db, unsigned int flags, 679 dns_dbiterator_t **iteratorp) { 680 /* 681 * Create an iterator for version 'version' of 'db'. 682 */ 683 684 REQUIRE(DNS_DB_VALID(db)); 685 REQUIRE(iteratorp != NULL && *iteratorp == NULL); 686 REQUIRE((flags & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) != 687 (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)); 688 689 if (db->methods->createiterator != NULL) { 690 return db->methods->createiterator(db, flags, iteratorp); 691 } 692 return ISC_R_NOTIMPLEMENTED; 693 } 694 695 /*** 696 *** Rdataset Methods 697 ***/ 698 699 isc_result_t 700 dns__db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 701 dns_rdatatype_t type, dns_rdatatype_t covers, 702 isc_stdtime_t now, dns_rdataset_t *rdataset, 703 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 704 REQUIRE(DNS_DB_VALID(db)); 705 REQUIRE(node != NULL); 706 REQUIRE(DNS_RDATASET_VALID(rdataset)); 707 REQUIRE(!dns_rdataset_isassociated(rdataset)); 708 REQUIRE(covers == dns_rdatatype_none || type == dns_rdatatype_rrsig || 709 type == dns_rdatatype_sig); 710 REQUIRE(type != dns_rdatatype_any); 711 REQUIRE(sigrdataset == NULL || 712 (DNS_RDATASET_VALID(sigrdataset) && 713 !dns_rdataset_isassociated(sigrdataset))); 714 715 return (db->methods->findrdataset)(db, node, version, type, covers, now, 716 rdataset, 717 sigrdataset DNS__DB_FLARG_PASS); 718 } 719 720 isc_result_t 721 dns__db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 722 unsigned int options, isc_stdtime_t now, 723 dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 724 /* 725 * Make '*iteratorp' an rdataset iteratator for all rdatasets at 726 * 'node' in version 'version' of 'db'. 727 */ 728 729 REQUIRE(DNS_DB_VALID(db)); 730 REQUIRE(iteratorp != NULL && *iteratorp == NULL); 731 732 return (db->methods->allrdatasets)(db, node, version, options, now, 733 iteratorp DNS__DB_FLARG_PASS); 734 } 735 736 isc_result_t 737 dns__db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 738 isc_stdtime_t now, dns_rdataset_t *rdataset, 739 unsigned int options, 740 dns_rdataset_t *addedrdataset DNS__DB_FLARG) { 741 /* 742 * Add 'rdataset' to 'node' in version 'version' of 'db'. 743 */ 744 745 REQUIRE(DNS_DB_VALID(db)); 746 REQUIRE(node != NULL); 747 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) || 748 ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL && 749 (options & DNS_DBADD_MERGE) == 0)); 750 REQUIRE((options & DNS_DBADD_EXACT) == 0 || 751 (options & DNS_DBADD_MERGE) != 0); 752 REQUIRE(DNS_RDATASET_VALID(rdataset)); 753 REQUIRE(dns_rdataset_isassociated(rdataset)); 754 REQUIRE(rdataset->rdclass == db->rdclass); 755 REQUIRE(addedrdataset == NULL || 756 (DNS_RDATASET_VALID(addedrdataset) && 757 !dns_rdataset_isassociated(addedrdataset))); 758 759 if (db->methods->addrdataset != NULL) { 760 return (db->methods->addrdataset)( 761 db, node, version, now, rdataset, options, 762 addedrdataset DNS__DB_FLARG_PASS); 763 } 764 return ISC_R_NOTIMPLEMENTED; 765 } 766 767 isc_result_t 768 dns__db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, 769 dns_dbversion_t *version, dns_rdataset_t *rdataset, 770 unsigned int options, 771 dns_rdataset_t *newrdataset DNS__DB_FLARG) { 772 /* 773 * Remove any rdata in 'rdataset' from 'node' in version 'version' of 774 * 'db'. 775 */ 776 777 REQUIRE(DNS_DB_VALID(db)); 778 REQUIRE(node != NULL); 779 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL); 780 REQUIRE(DNS_RDATASET_VALID(rdataset)); 781 REQUIRE(dns_rdataset_isassociated(rdataset)); 782 REQUIRE(rdataset->rdclass == db->rdclass); 783 REQUIRE(newrdataset == NULL || 784 (DNS_RDATASET_VALID(newrdataset) && 785 !dns_rdataset_isassociated(newrdataset))); 786 787 if (db->methods->subtractrdataset != NULL) { 788 return (db->methods->subtractrdataset)( 789 db, node, version, rdataset, options, 790 newrdataset DNS__DB_FLARG_PASS); 791 } 792 return ISC_R_NOTIMPLEMENTED; 793 } 794 795 isc_result_t 796 dns__db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, 797 dns_dbversion_t *version, dns_rdatatype_t type, 798 dns_rdatatype_t covers DNS__DB_FLARG) { 799 /* 800 * Make it so that no rdataset of type 'type' exists at 'node' in 801 * version version 'version' of 'db'. 802 */ 803 804 REQUIRE(DNS_DB_VALID(db)); 805 REQUIRE(node != NULL); 806 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) || 807 ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL)); 808 809 if (db->methods->deleterdataset != NULL) { 810 return (db->methods->deleterdataset)(db, node, version, type, 811 covers DNS__DB_FLARG_PASS); 812 } 813 return ISC_R_NOTIMPLEMENTED; 814 } 815 816 isc_result_t 817 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) { 818 isc_result_t result; 819 dns_dbnode_t *node = NULL; 820 dns_rdataset_t rdataset; 821 dns_rdata_t rdata = DNS_RDATA_INIT; 822 isc_buffer_t buffer; 823 824 REQUIRE(dns_db_iszone(db) || dns_db_isstub(db)); 825 826 result = dns_db_findnode(db, dns_db_origin(db), false, &node); 827 if (result != ISC_R_SUCCESS) { 828 return result; 829 } 830 831 dns_rdataset_init(&rdataset); 832 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0, 833 (isc_stdtime_t)0, &rdataset, NULL); 834 if (result != ISC_R_SUCCESS) { 835 goto freenode; 836 } 837 838 result = dns_rdataset_first(&rdataset); 839 if (result != ISC_R_SUCCESS) { 840 goto freerdataset; 841 } 842 dns_rdataset_current(&rdataset, &rdata); 843 result = dns_rdataset_next(&rdataset); 844 INSIST(result == ISC_R_NOMORE); 845 846 INSIST(rdata.length > 20); 847 isc_buffer_init(&buffer, rdata.data, rdata.length); 848 isc_buffer_add(&buffer, rdata.length); 849 isc_buffer_forward(&buffer, rdata.length - 20); 850 *serialp = isc_buffer_getuint32(&buffer); 851 852 result = ISC_R_SUCCESS; 853 854 freerdataset: 855 dns_rdataset_disassociate(&rdataset); 856 857 freenode: 858 dns_db_detachnode(db, &node); 859 return result; 860 } 861 862 unsigned int 863 dns_db_nodecount(dns_db_t *db, dns_dbtree_t tree) { 864 REQUIRE(DNS_DB_VALID(db)); 865 866 if (db->methods->nodecount != NULL) { 867 return (db->methods->nodecount)(db, tree); 868 } 869 return 0; 870 } 871 872 size_t 873 dns_db_hashsize(dns_db_t *db) { 874 REQUIRE(DNS_DB_VALID(db)); 875 876 if (db->methods->hashsize == NULL) { 877 return 0; 878 } 879 880 return (db->methods->hashsize)(db); 881 } 882 883 void 884 dns_db_setloop(dns_db_t *db, isc_loop_t *loop) { 885 REQUIRE(DNS_DB_VALID(db)); 886 887 if (db->methods->setloop != NULL) { 888 (db->methods->setloop)(db, loop); 889 } 890 } 891 892 isc_result_t 893 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, 894 isc_mem_t *mctx, dns_dbimplementation_t **dbimp) { 895 dns_dbimplementation_t *imp; 896 897 REQUIRE(name != NULL); 898 REQUIRE(dbimp != NULL && *dbimp == NULL); 899 900 isc_once_do(&once, initialize); 901 902 RWLOCK(&implock, isc_rwlocktype_write); 903 imp = impfind(name); 904 if (imp != NULL) { 905 RWUNLOCK(&implock, isc_rwlocktype_write); 906 return ISC_R_EXISTS; 907 } 908 909 imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t)); 910 imp->name = name; 911 imp->create = create; 912 imp->mctx = NULL; 913 imp->driverarg = driverarg; 914 isc_mem_attach(mctx, &imp->mctx); 915 ISC_LINK_INIT(imp, link); 916 ISC_LIST_APPEND(implementations, imp, link); 917 RWUNLOCK(&implock, isc_rwlocktype_write); 918 919 *dbimp = imp; 920 921 return ISC_R_SUCCESS; 922 } 923 924 void 925 dns_db_unregister(dns_dbimplementation_t **dbimp) { 926 dns_dbimplementation_t *imp; 927 928 REQUIRE(dbimp != NULL && *dbimp != NULL); 929 930 isc_once_do(&once, initialize); 931 932 imp = *dbimp; 933 *dbimp = NULL; 934 RWLOCK(&implock, isc_rwlocktype_write); 935 ISC_LIST_UNLINK(implementations, imp, link); 936 isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t)); 937 RWUNLOCK(&implock, isc_rwlocktype_write); 938 ENSURE(*dbimp == NULL); 939 } 940 941 isc_result_t 942 dns__db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 943 REQUIRE(DNS_DB_VALID(db)); 944 REQUIRE(dns_db_iszone(db)); 945 REQUIRE(nodep != NULL && *nodep == NULL); 946 947 if (db->methods->getoriginnode != NULL) { 948 return (db->methods->getoriginnode)(db, 949 nodep DNS__DB_FLARG_PASS); 950 } 951 952 return ISC_R_NOTFOUND; 953 } 954 955 dns_stats_t * 956 dns_db_getrrsetstats(dns_db_t *db) { 957 REQUIRE(DNS_DB_VALID(db)); 958 959 if (db->methods->getrrsetstats != NULL) { 960 return (db->methods->getrrsetstats)(db); 961 } 962 963 return NULL; 964 } 965 966 isc_result_t 967 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) { 968 REQUIRE(DNS_DB_VALID(db)); 969 970 if (db->methods->setcachestats != NULL) { 971 return (db->methods->setcachestats)(db, stats); 972 } 973 974 return ISC_R_NOTIMPLEMENTED; 975 } 976 977 isc_result_t 978 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, 979 dns_hash_t *hash, uint8_t *flags, 980 uint16_t *iterations, unsigned char *salt, 981 size_t *salt_length) { 982 REQUIRE(DNS_DB_VALID(db)); 983 REQUIRE(dns_db_iszone(db)); 984 985 if (db->methods->getnsec3parameters != NULL) { 986 return (db->methods->getnsec3parameters)(db, version, hash, 987 flags, iterations, 988 salt, salt_length); 989 } 990 991 return ISC_R_NOTFOUND; 992 } 993 994 isc_result_t 995 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records, 996 uint64_t *bytes) { 997 REQUIRE(DNS_DB_VALID(db)); 998 REQUIRE(dns_db_iszone(db)); 999 1000 if (db->methods->getsize != NULL) { 1001 return (db->methods->getsize)(db, version, records, bytes); 1002 } 1003 1004 return ISC_R_NOTFOUND; 1005 } 1006 1007 isc_result_t 1008 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, 1009 isc_stdtime_t resign) { 1010 if (db->methods->setsigningtime != NULL) { 1011 return (db->methods->setsigningtime)(db, rdataset, resign); 1012 } 1013 return ISC_R_NOTIMPLEMENTED; 1014 } 1015 1016 isc_result_t 1017 dns_db_getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *name, 1018 dns_typepair_t *typepair) { 1019 if (db->methods->getsigningtime != NULL) { 1020 return (db->methods->getsigningtime)(db, resign, name, 1021 typepair); 1022 } 1023 return ISC_R_NOTFOUND; 1024 } 1025 1026 static void 1027 call_updatenotify(dns_db_t *db) { 1028 rcu_read_lock(); 1029 struct cds_lfht *update_listeners = 1030 rcu_dereference(db->update_listeners); 1031 if (update_listeners != NULL) { 1032 struct cds_lfht_iter iter; 1033 dns_dbonupdatelistener_t *listener; 1034 cds_lfht_for_each_entry(update_listeners, &iter, listener, 1035 ht_node) { 1036 if (!cds_lfht_is_node_deleted(&listener->ht_node)) { 1037 listener->onupdate(db, listener->onupdate_arg); 1038 } 1039 } 1040 } 1041 rcu_read_unlock(); 1042 } 1043 1044 static void 1045 updatenotify_free(struct rcu_head *rcu_head) { 1046 dns_dbonupdatelistener_t *listener = 1047 caa_container_of(rcu_head, dns_dbonupdatelistener_t, rcu_head); 1048 isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); 1049 } 1050 1051 static int 1052 updatenotify_match(struct cds_lfht_node *ht_node, const void *_key) { 1053 const dns_dbonupdatelistener_t *listener = 1054 caa_container_of(ht_node, dns_dbonupdatelistener_t, ht_node); 1055 const dns_dbonupdatelistener_t *key = _key; 1056 1057 return listener->onupdate == key->onupdate && 1058 listener->onupdate_arg == key->onupdate_arg; 1059 } 1060 1061 /* 1062 * Attach a notify-on-update function the database 1063 */ 1064 void 1065 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn, 1066 void *fn_arg) { 1067 REQUIRE(db != NULL); 1068 REQUIRE(fn != NULL); 1069 1070 dns_dbonupdatelistener_t key = { .onupdate = fn, 1071 .onupdate_arg = fn_arg }; 1072 uint32_t hash = isc_hash32(&key, sizeof(key), true); 1073 dns_dbonupdatelistener_t *listener = isc_mem_get(db->mctx, 1074 sizeof(*listener)); 1075 *listener = key; 1076 1077 isc_mem_attach(db->mctx, &listener->mctx); 1078 1079 rcu_read_lock(); 1080 struct cds_lfht *update_listeners = 1081 rcu_dereference(db->update_listeners); 1082 INSIST(update_listeners != NULL); 1083 struct cds_lfht_node *ht_node = 1084 cds_lfht_add_unique(update_listeners, hash, updatenotify_match, 1085 &key, &listener->ht_node); 1086 rcu_read_unlock(); 1087 1088 if (ht_node != &listener->ht_node) { 1089 updatenotify_free(&listener->rcu_head); 1090 } 1091 } 1092 1093 void 1094 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn, 1095 void *fn_arg) { 1096 REQUIRE(db != NULL); 1097 1098 dns_dbonupdatelistener_t key = { .onupdate = fn, 1099 .onupdate_arg = fn_arg }; 1100 uint32_t hash = isc_hash32(&key, sizeof(key), true); 1101 struct cds_lfht_iter iter; 1102 1103 rcu_read_lock(); 1104 struct cds_lfht *update_listeners = 1105 rcu_dereference(db->update_listeners); 1106 INSIST(update_listeners != NULL); 1107 cds_lfht_lookup(update_listeners, hash, updatenotify_match, &key, 1108 &iter); 1109 1110 struct cds_lfht_node *ht_node = cds_lfht_iter_get_node(&iter); 1111 if (ht_node != NULL && !cds_lfht_del(update_listeners, ht_node)) { 1112 dns_dbonupdatelistener_t *listener = caa_container_of( 1113 ht_node, dns_dbonupdatelistener_t, ht_node); 1114 call_rcu(&listener->rcu_head, updatenotify_free); 1115 } 1116 rcu_read_unlock(); 1117 } 1118 1119 isc_result_t 1120 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) { 1121 REQUIRE(DNS_DB_VALID(db)); 1122 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1123 1124 if (db->methods->setservestalettl != NULL) { 1125 return (db->methods->setservestalettl)(db, ttl); 1126 } 1127 return ISC_R_NOTIMPLEMENTED; 1128 } 1129 1130 isc_result_t 1131 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) { 1132 REQUIRE(DNS_DB_VALID(db)); 1133 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1134 1135 if (db->methods->getservestalettl != NULL) { 1136 return (db->methods->getservestalettl)(db, ttl); 1137 } 1138 return ISC_R_NOTIMPLEMENTED; 1139 } 1140 1141 isc_result_t 1142 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) { 1143 REQUIRE(DNS_DB_VALID(db)); 1144 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1145 1146 if (db->methods->setservestalerefresh != NULL) { 1147 return (db->methods->setservestalerefresh)(db, interval); 1148 } 1149 return ISC_R_NOTIMPLEMENTED; 1150 } 1151 1152 isc_result_t 1153 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) { 1154 REQUIRE(DNS_DB_VALID(db)); 1155 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 1156 1157 if (db->methods->getservestalerefresh != NULL) { 1158 return (db->methods->getservestalerefresh)(db, interval); 1159 } 1160 return ISC_R_NOTIMPLEMENTED; 1161 } 1162 1163 isc_result_t 1164 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) { 1165 REQUIRE(dns_db_iszone(db)); 1166 REQUIRE(stats != NULL); 1167 1168 if (db->methods->setgluecachestats != NULL) { 1169 return (db->methods->setgluecachestats)(db, stats); 1170 } 1171 1172 return ISC_R_NOTIMPLEMENTED; 1173 } 1174 1175 isc_result_t 1176 dns_db_addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset, 1177 dns_message_t *msg) { 1178 REQUIRE(DNS_DB_VALID(db)); 1179 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 1180 REQUIRE(DNS_RDATASET_VALID(rdataset)); 1181 REQUIRE(rdataset->methods != NULL); 1182 REQUIRE(rdataset->type == dns_rdatatype_ns); 1183 1184 if (db->methods->addglue != NULL) { 1185 (db->methods->addglue)(db, version, rdataset, msg); 1186 1187 return ISC_R_SUCCESS; 1188 } 1189 1190 return ISC_R_NOTIMPLEMENTED; 1191 } 1192 1193 void 1194 dns_db_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) { 1195 if (db->methods->locknode != NULL) { 1196 (db->methods->locknode)(db, node, type); 1197 } 1198 } 1199 1200 void 1201 dns_db_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) { 1202 if (db->methods->unlocknode != NULL) { 1203 (db->methods->unlocknode)(db, node, type); 1204 } 1205 } 1206 1207 void 1208 dns_db_expiredata(dns_db_t *db, dns_dbnode_t *node, void *data) { 1209 if (db->methods->expiredata != NULL) { 1210 (db->methods->expiredata)(db, node, data); 1211 } 1212 } 1213 1214 void 1215 dns_db_deletedata(dns_db_t *db, dns_dbnode_t *node, void *data) { 1216 if (db->methods->deletedata != NULL) { 1217 (db->methods->deletedata)(db, node, data); 1218 } 1219 } 1220 1221 isc_result_t 1222 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { 1223 REQUIRE(db != NULL); 1224 REQUIRE(node != NULL); 1225 REQUIRE(name != NULL); 1226 1227 if (db->methods->nodefullname != NULL) { 1228 return (db->methods->nodefullname)(db, node, name); 1229 } 1230 return ISC_R_NOTIMPLEMENTED; 1231 } 1232 1233 void 1234 dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) { 1235 REQUIRE(DNS_DB_VALID(db)); 1236 1237 if (db->methods->setmaxrrperset != NULL) { 1238 (db->methods->setmaxrrperset)(db, value); 1239 } 1240 } 1241 1242 void 1243 dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) { 1244 REQUIRE(DNS_DB_VALID(db)); 1245 1246 if (db->methods->setmaxtypepername != NULL) { 1247 (db->methods->setmaxtypepername)(db, value); 1248 } 1249 } 1250 1251 void 1252 dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name, 1253 dns_rdatatype_t type, const char *op, 1254 uint32_t limit) { 1255 char namebuf[DNS_NAME_FORMATSIZE]; 1256 char originbuf[DNS_NAME_FORMATSIZE]; 1257 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 1258 char clsbuf[DNS_RDATACLASS_FORMATSIZE]; 1259 1260 dns_name_format(name, namebuf, sizeof(namebuf)); 1261 dns_name_format(&db->origin, originbuf, sizeof(originbuf)); 1262 dns_rdatatype_format(type, typebuf, sizeof(typebuf)); 1263 dns_rdataclass_format(db->rdclass, clsbuf, sizeof(clsbuf)); 1264 1265 isc_log_write( 1266 dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB, 1267 ISC_LOG_ERROR, 1268 "error %s '%s/%s' in '%s/%s' (%s): %s (must not exceed %u)", op, 1269 namebuf, typebuf, originbuf, clsbuf, 1270 (db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone", 1271 isc_result_totext(DNS_R_TOOMANYRECORDS), limit); 1272 } 1273 1274 void 1275 dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue) { 1276 while (glue != NULL) { 1277 dns_glue_t *next = glue->next; 1278 1279 if (dns_rdataset_isassociated(&glue->rdataset_a)) { 1280 dns_rdataset_disassociate(&glue->rdataset_a); 1281 } 1282 if (dns_rdataset_isassociated(&glue->sigrdataset_a)) { 1283 dns_rdataset_disassociate(&glue->sigrdataset_a); 1284 } 1285 1286 if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { 1287 dns_rdataset_disassociate(&glue->rdataset_aaaa); 1288 } 1289 if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) { 1290 dns_rdataset_disassociate(&glue->sigrdataset_aaaa); 1291 } 1292 1293 dns_rdataset_invalidate(&glue->rdataset_a); 1294 dns_rdataset_invalidate(&glue->sigrdataset_a); 1295 dns_rdataset_invalidate(&glue->rdataset_aaaa); 1296 dns_rdataset_invalidate(&glue->sigrdataset_aaaa); 1297 1298 dns_name_free(&glue->name, mctx); 1299 1300 isc_mem_put(mctx, glue, sizeof(*glue)); 1301 1302 glue = next; 1303 } 1304 } 1305 1306 void 1307 dns__db_destroy_gluelist(dns_gluelist_t **gluelistp) { 1308 REQUIRE(gluelistp != NULL); 1309 if (*gluelistp == NULL) { 1310 return; 1311 } 1312 1313 dns_gluelist_t *gluelist = *gluelistp; 1314 1315 dns__db_free_glue(gluelist->mctx, gluelist->glue); 1316 1317 isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist)); 1318 } 1319 1320 void 1321 dns__db_free_gluelist_rcu(struct rcu_head *rcu_head) { 1322 dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t, 1323 rcu_head); 1324 dns__db_destroy_gluelist(&gluelist); 1325 } 1326 1327 void 1328 dns__db_cleanup_gluelists(struct cds_wfs_stack *glue_stack) { 1329 struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack); 1330 struct cds_wfs_node *node = NULL, *next = NULL; 1331 1332 rcu_read_lock(); 1333 cds_wfs_for_each_blocking_safe(head, node, next) { 1334 dns_gluelist_t *gluelist = 1335 caa_container_of(node, dns_gluelist_t, wfs_node); 1336 dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header, 1337 NULL); 1338 (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL); 1339 1340 call_rcu(&gluelist->rcu_head, dns__db_free_gluelist_rcu); 1341 } 1342 rcu_read_unlock(); 1343 } 1344 1345 #define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0) 1346 1347 static void 1348 addglue_to_message(dns_glue_t *ge, dns_message_t *msg) { 1349 for (; ge != NULL; ge = ge->next) { 1350 dns_name_t *name = NULL; 1351 dns_rdataset_t *rdataset_a = NULL; 1352 dns_rdataset_t *sigrdataset_a = NULL; 1353 dns_rdataset_t *rdataset_aaaa = NULL; 1354 dns_rdataset_t *sigrdataset_aaaa = NULL; 1355 bool prepend_name = false; 1356 1357 dns_message_gettempname(msg, &name); 1358 1359 dns_name_copy(&ge->name, name); 1360 1361 if (dns_rdataset_isassociated(&ge->rdataset_a)) { 1362 dns_message_gettemprdataset(msg, &rdataset_a); 1363 } 1364 1365 if (dns_rdataset_isassociated(&ge->sigrdataset_a)) { 1366 dns_message_gettemprdataset(msg, &sigrdataset_a); 1367 } 1368 1369 if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) { 1370 dns_message_gettemprdataset(msg, &rdataset_aaaa); 1371 } 1372 1373 if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) { 1374 dns_message_gettemprdataset(msg, &sigrdataset_aaaa); 1375 } 1376 1377 if (rdataset_a != NULL) { 1378 dns_rdataset_clone(&ge->rdataset_a, rdataset_a); 1379 ISC_LIST_APPEND(name->list, rdataset_a, link); 1380 if (IS_REQUIRED_GLUE(rdataset_a)) { 1381 prepend_name = true; 1382 } 1383 } 1384 1385 if (sigrdataset_a != NULL) { 1386 dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a); 1387 ISC_LIST_APPEND(name->list, sigrdataset_a, link); 1388 } 1389 1390 if (rdataset_aaaa != NULL) { 1391 dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa); 1392 ISC_LIST_APPEND(name->list, rdataset_aaaa, link); 1393 if (IS_REQUIRED_GLUE(rdataset_aaaa)) { 1394 prepend_name = true; 1395 } 1396 } 1397 if (sigrdataset_aaaa != NULL) { 1398 dns_rdataset_clone(&ge->sigrdataset_aaaa, 1399 sigrdataset_aaaa); 1400 ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link); 1401 } 1402 1403 dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); 1404 1405 /* 1406 * When looking for required glue, dns_message_rendersection() 1407 * only processes the first rdataset associated with the first 1408 * name added to the ADDITIONAL section. dns_message_addname() 1409 * performs an append on the list of names in a given section, 1410 * so if any glue record was marked as required, we need to 1411 * move the name it is associated with to the beginning of the 1412 * list for the ADDITIONAL section or else required glue might 1413 * not be rendered. 1414 */ 1415 if (prepend_name) { 1416 ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL], 1417 name, link); 1418 ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL], 1419 name, link); 1420 } 1421 } 1422 } 1423 1424 static dns_gluelist_t * 1425 new_gluelist(dns_db_t *db, dns_slabheader_t *header, 1426 const dns_dbversion_t *dbversion) { 1427 dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist)); 1428 *gluelist = (dns_gluelist_t){ 1429 .version = dbversion, 1430 .header = header, 1431 }; 1432 1433 isc_mem_attach(db->mctx, &gluelist->mctx); 1434 1435 cds_wfs_node_init(&gluelist->wfs_node); 1436 1437 return gluelist; 1438 } 1439 1440 static dns_gluelist_t * 1441 create_gluelist(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *dbnode, 1442 dns_rdataset_t *rdataset, dns_additionaldatafunc_t add) { 1443 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1444 dns_glue_additionaldata_ctx_t ctx = { 1445 .db = db, 1446 .version = dbversion, 1447 .node = dbnode, 1448 }; 1449 dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version); 1450 1451 /* 1452 * Get the owner name of the NS RRset - it will be necessary for 1453 * identifying required glue in glue_nsdname_cb() (by 1454 * determining which NS records in the delegation are 1455 * in-bailiwick). 1456 */ 1457 1458 (void)dns_rdataset_additionaldata(rdataset, dns_rootname, add, &ctx, 0); 1459 1460 CMM_STORE_SHARED(gluelist->glue, ctx.glue); 1461 1462 return gluelist; 1463 } 1464 1465 isc_result_t 1466 dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion, 1467 dns_rdataset_t *rdataset, dns_message_t *msg, 1468 dns_additionaldatafunc_t add, 1469 struct cds_wfs_stack *glue_stack) { 1470 dns_dbnode_t *dbnode = (dns_dbnode_t *)rdataset->slab.node; 1471 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1472 dns_glue_t *glue = NULL; 1473 isc_result_t result = ISC_R_SUCCESS; 1474 1475 REQUIRE(rdataset->type == dns_rdatatype_ns); 1476 1477 rcu_read_lock(); 1478 1479 dns_gluelist_t *gluelist = rcu_dereference(header->gluelist); 1480 if (gluelist == NULL || gluelist->version != dbversion) { 1481 /* No or old glue list was found in the table. */ 1482 1483 dns_gluelist_t *xchg_gluelist = gluelist; 1484 dns_gluelist_t *old_gluelist = (void *)-1; 1485 dns_gluelist_t *new_gluelist = 1486 create_gluelist(db, dbversion, dbnode, rdataset, add); 1487 1488 while (old_gluelist != xchg_gluelist && 1489 (xchg_gluelist == NULL || 1490 xchg_gluelist->version != dbversion)) 1491 { 1492 old_gluelist = xchg_gluelist; 1493 xchg_gluelist = rcu_cmpxchg_pointer( 1494 &header->gluelist, old_gluelist, new_gluelist); 1495 } 1496 1497 if (old_gluelist == xchg_gluelist) { 1498 /* CAS was successful */ 1499 cds_wfs_push(glue_stack, &new_gluelist->wfs_node); 1500 gluelist = new_gluelist; 1501 } else { 1502 dns__db_destroy_gluelist(&new_gluelist); 1503 gluelist = xchg_gluelist; 1504 } 1505 } 1506 1507 glue = CMM_LOAD_SHARED(gluelist->glue); 1508 1509 if (glue != NULL) { 1510 addglue_to_message(glue, msg); 1511 result = ISC_R_NOTFOUND; 1512 } 1513 1514 rcu_read_unlock(); 1515 1516 return result; 1517 } 1518 1519 dns_glue_t * 1520 dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name) { 1521 dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue)); 1522 *glue = (dns_glue_t){ 1523 .name = DNS_NAME_INITEMPTY, 1524 }; 1525 1526 dns_name_dup(name, mctx, &glue->name); 1527 1528 return glue; 1529 } 1530