1 /* $NetBSD: nta.c,v 1.8 2022/09/23 12:15:30 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 #include <inttypes.h> 19 #include <stdbool.h> 20 21 #include <isc/buffer.h> 22 #include <isc/log.h> 23 #include <isc/mem.h> 24 #include <isc/print.h> 25 #include <isc/rwlock.h> 26 #include <isc/string.h> 27 #include <isc/task.h> 28 #include <isc/time.h> 29 #include <isc/timer.h> 30 #include <isc/util.h> 31 32 #include <dns/db.h> 33 #include <dns/fixedname.h> 34 #include <dns/log.h> 35 #include <dns/name.h> 36 #include <dns/nta.h> 37 #include <dns/rbt.h> 38 #include <dns/rdataset.h> 39 #include <dns/resolver.h> 40 #include <dns/result.h> 41 #include <dns/time.h> 42 43 struct dns_nta { 44 unsigned int magic; 45 isc_refcount_t refcount; 46 dns_ntatable_t *ntatable; 47 bool forced; 48 isc_timer_t *timer; 49 dns_fetch_t *fetch; 50 dns_rdataset_t rdataset; 51 dns_rdataset_t sigrdataset; 52 dns_fixedname_t fn; 53 dns_name_t *name; 54 isc_stdtime_t expiry; 55 }; 56 57 #define NTA_MAGIC ISC_MAGIC('N', 'T', 'A', 'n') 58 #define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC) 59 60 /* 61 * Obtain a reference to the nta object. Released by 62 * nta_detach. 63 */ 64 static void 65 nta_ref(dns_nta_t *nta) { 66 isc_refcount_increment(&nta->refcount); 67 } 68 69 static void 70 nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) { 71 REQUIRE(ntap != NULL && VALID_NTA(*ntap)); 72 dns_nta_t *nta = *ntap; 73 *ntap = NULL; 74 75 if (isc_refcount_decrement(&nta->refcount) == 1) { 76 isc_refcount_destroy(&nta->refcount); 77 nta->magic = 0; 78 if (nta->timer != NULL) { 79 (void)isc_timer_reset(nta->timer, 80 isc_timertype_inactive, NULL, 81 NULL, true); 82 isc_timer_detach(&nta->timer); 83 } 84 if (dns_rdataset_isassociated(&nta->rdataset)) { 85 dns_rdataset_disassociate(&nta->rdataset); 86 } 87 if (dns_rdataset_isassociated(&nta->sigrdataset)) { 88 dns_rdataset_disassociate(&nta->sigrdataset); 89 } 90 if (nta->fetch != NULL) { 91 dns_resolver_cancelfetch(nta->fetch); 92 dns_resolver_destroyfetch(&nta->fetch); 93 } 94 isc_mem_put(mctx, nta, sizeof(dns_nta_t)); 95 } 96 } 97 98 static void 99 free_nta(void *data, void *arg) { 100 dns_nta_t *nta = (dns_nta_t *)data; 101 isc_mem_t *mctx = (isc_mem_t *)arg; 102 103 nta_detach(mctx, &nta); 104 } 105 106 isc_result_t 107 dns_ntatable_create(dns_view_t *view, isc_taskmgr_t *taskmgr, 108 isc_timermgr_t *timermgr, dns_ntatable_t **ntatablep) { 109 dns_ntatable_t *ntatable; 110 isc_result_t result; 111 112 REQUIRE(ntatablep != NULL && *ntatablep == NULL); 113 114 ntatable = isc_mem_get(view->mctx, sizeof(*ntatable)); 115 116 ntatable->task = NULL; 117 result = isc_task_create(taskmgr, 0, &ntatable->task); 118 if (result != ISC_R_SUCCESS) { 119 goto cleanup_ntatable; 120 } 121 isc_task_setname(ntatable->task, "ntatable", ntatable); 122 123 ntatable->table = NULL; 124 result = dns_rbt_create(view->mctx, free_nta, view->mctx, 125 &ntatable->table); 126 if (result != ISC_R_SUCCESS) { 127 goto cleanup_task; 128 } 129 130 isc_rwlock_init(&ntatable->rwlock, 0, 0); 131 132 ntatable->shuttingdown = false; 133 ntatable->timermgr = timermgr; 134 ntatable->taskmgr = taskmgr; 135 136 ntatable->view = view; 137 isc_refcount_init(&ntatable->references, 1); 138 139 ntatable->magic = NTATABLE_MAGIC; 140 *ntatablep = ntatable; 141 142 return (ISC_R_SUCCESS); 143 144 cleanup_task: 145 isc_task_detach(&ntatable->task); 146 147 cleanup_ntatable: 148 isc_mem_put(view->mctx, ntatable, sizeof(*ntatable)); 149 150 return (result); 151 } 152 153 void 154 dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp) { 155 REQUIRE(VALID_NTATABLE(source)); 156 REQUIRE(targetp != NULL && *targetp == NULL); 157 158 isc_refcount_increment(&source->references); 159 160 *targetp = source; 161 } 162 163 void 164 dns_ntatable_detach(dns_ntatable_t **ntatablep) { 165 dns_ntatable_t *ntatable; 166 167 REQUIRE(ntatablep != NULL && VALID_NTATABLE(*ntatablep)); 168 169 ntatable = *ntatablep; 170 *ntatablep = NULL; 171 172 if (isc_refcount_decrement(&ntatable->references) == 1) { 173 dns_rbt_destroy(&ntatable->table); 174 isc_rwlock_destroy(&ntatable->rwlock); 175 isc_refcount_destroy(&ntatable->references); 176 if (ntatable->task != NULL) { 177 isc_task_detach(&ntatable->task); 178 } 179 ntatable->timermgr = NULL; 180 ntatable->taskmgr = NULL; 181 ntatable->magic = 0; 182 isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable)); 183 } 184 } 185 186 static void 187 fetch_done(isc_task_t *task, isc_event_t *event) { 188 dns_fetchevent_t *devent = (dns_fetchevent_t *)event; 189 dns_nta_t *nta = devent->ev_arg; 190 isc_result_t eresult = devent->result; 191 dns_ntatable_t *ntatable = nta->ntatable; 192 dns_view_t *view = ntatable->view; 193 isc_stdtime_t now; 194 195 UNUSED(task); 196 197 if (dns_rdataset_isassociated(&nta->rdataset)) { 198 dns_rdataset_disassociate(&nta->rdataset); 199 } 200 if (dns_rdataset_isassociated(&nta->sigrdataset)) { 201 dns_rdataset_disassociate(&nta->sigrdataset); 202 } 203 if (nta->fetch == devent->fetch) { 204 nta->fetch = NULL; 205 } 206 dns_resolver_destroyfetch(&devent->fetch); 207 208 if (devent->node != NULL) { 209 dns_db_detachnode(devent->db, &devent->node); 210 } 211 if (devent->db != NULL) { 212 dns_db_detach(&devent->db); 213 } 214 215 isc_event_free(&event); 216 isc_stdtime_get(&now); 217 218 switch (eresult) { 219 case ISC_R_SUCCESS: 220 case DNS_R_NCACHENXDOMAIN: 221 case DNS_R_NXDOMAIN: 222 case DNS_R_NCACHENXRRSET: 223 case DNS_R_NXRRSET: 224 if (nta->expiry > now) { 225 nta->expiry = now; 226 } 227 break; 228 default: 229 break; 230 } 231 232 /* 233 * If we're expiring before the next recheck, we might 234 * as well stop the timer now. 235 */ 236 if (nta->timer != NULL && nta->expiry - now < view->nta_recheck) { 237 (void)isc_timer_reset(nta->timer, isc_timertype_inactive, NULL, 238 NULL, true); 239 } 240 nta_detach(view->mctx, &nta); 241 dns_view_weakdetach(&view); 242 } 243 244 static void 245 checkbogus(isc_task_t *task, isc_event_t *event) { 246 dns_nta_t *nta = event->ev_arg; 247 dns_ntatable_t *ntatable = nta->ntatable; 248 dns_view_t *view = NULL; 249 isc_result_t result; 250 251 if (nta->fetch != NULL) { 252 dns_resolver_cancelfetch(nta->fetch); 253 nta->fetch = NULL; 254 } 255 if (dns_rdataset_isassociated(&nta->rdataset)) { 256 dns_rdataset_disassociate(&nta->rdataset); 257 } 258 if (dns_rdataset_isassociated(&nta->sigrdataset)) { 259 dns_rdataset_disassociate(&nta->sigrdataset); 260 } 261 262 isc_event_free(&event); 263 264 nta_ref(nta); 265 dns_view_weakattach(ntatable->view, &view); 266 result = dns_resolver_createfetch( 267 view->resolver, nta->name, dns_rdatatype_nsec, NULL, NULL, NULL, 268 NULL, 0, DNS_FETCHOPT_NONTA, 0, NULL, task, fetch_done, nta, 269 &nta->rdataset, &nta->sigrdataset, &nta->fetch); 270 if (result != ISC_R_SUCCESS) { 271 nta_detach(view->mctx, &nta); 272 dns_view_weakdetach(&view); 273 } 274 } 275 276 static isc_result_t 277 settimer(dns_ntatable_t *ntatable, dns_nta_t *nta, uint32_t lifetime) { 278 isc_result_t result; 279 isc_interval_t interval; 280 dns_view_t *view; 281 282 REQUIRE(VALID_NTATABLE(ntatable)); 283 REQUIRE(VALID_NTA(nta)); 284 285 if (ntatable->timermgr == NULL) { 286 return (ISC_R_SUCCESS); 287 } 288 289 view = ntatable->view; 290 if (view->nta_recheck == 0 || lifetime <= view->nta_recheck) { 291 return (ISC_R_SUCCESS); 292 } 293 294 isc_interval_set(&interval, view->nta_recheck, 0); 295 result = isc_timer_create(ntatable->timermgr, isc_timertype_ticker, 296 NULL, &interval, ntatable->task, checkbogus, 297 nta, &nta->timer); 298 return (result); 299 } 300 301 static isc_result_t 302 nta_create(dns_ntatable_t *ntatable, const dns_name_t *name, 303 dns_nta_t **target) { 304 dns_nta_t *nta = NULL; 305 dns_view_t *view; 306 307 REQUIRE(VALID_NTATABLE(ntatable)); 308 REQUIRE(target != NULL && *target == NULL); 309 310 view = ntatable->view; 311 312 nta = isc_mem_get(view->mctx, sizeof(dns_nta_t)); 313 314 nta->ntatable = ntatable; 315 nta->expiry = 0; 316 nta->timer = NULL; 317 nta->fetch = NULL; 318 dns_rdataset_init(&nta->rdataset); 319 dns_rdataset_init(&nta->sigrdataset); 320 321 isc_refcount_init(&nta->refcount, 1); 322 323 nta->name = dns_fixedname_initname(&nta->fn); 324 dns_name_copynf(name, nta->name); 325 326 nta->magic = NTA_MAGIC; 327 328 *target = nta; 329 return (ISC_R_SUCCESS); 330 } 331 332 isc_result_t 333 dns_ntatable_add(dns_ntatable_t *ntatable, const dns_name_t *name, bool force, 334 isc_stdtime_t now, uint32_t lifetime) { 335 isc_result_t result = ISC_R_SUCCESS; 336 dns_nta_t *nta = NULL; 337 dns_rbtnode_t *node; 338 dns_view_t *view; 339 340 REQUIRE(VALID_NTATABLE(ntatable)); 341 342 view = ntatable->view; 343 344 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write); 345 346 if (ntatable->shuttingdown) { 347 goto unlock; 348 } 349 350 result = nta_create(ntatable, name, &nta); 351 if (result != ISC_R_SUCCESS) { 352 goto unlock; 353 } 354 355 nta->expiry = now + lifetime; 356 nta->forced = force; 357 358 node = NULL; 359 result = dns_rbt_addnode(ntatable->table, name, &node); 360 if (result == ISC_R_SUCCESS) { 361 if (!force) { 362 (void)settimer(ntatable, nta, lifetime); 363 } 364 node->data = nta; 365 nta = NULL; 366 } else if (result == ISC_R_EXISTS) { 367 dns_nta_t *n = node->data; 368 if (n == NULL) { 369 if (!force) { 370 (void)settimer(ntatable, nta, lifetime); 371 } 372 node->data = nta; 373 nta = NULL; 374 } else { 375 n->expiry = nta->expiry; 376 nta_detach(view->mctx, &nta); 377 } 378 result = ISC_R_SUCCESS; 379 } 380 381 unlock: 382 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write); 383 384 if (nta != NULL) { 385 nta_detach(view->mctx, &nta); 386 } 387 388 return (result); 389 } 390 391 /* 392 * Caller must hold a write lock on rwlock. 393 */ 394 static isc_result_t 395 deletenode(dns_ntatable_t *ntatable, const dns_name_t *name) { 396 isc_result_t result; 397 dns_rbtnode_t *node = NULL; 398 399 REQUIRE(VALID_NTATABLE(ntatable)); 400 REQUIRE(name != NULL); 401 402 result = dns_rbt_findnode(ntatable->table, name, NULL, &node, NULL, 403 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 404 if (result == ISC_R_SUCCESS) { 405 if (node->data != NULL) { 406 result = dns_rbt_deletenode(ntatable->table, node, 407 false); 408 } else { 409 result = ISC_R_NOTFOUND; 410 } 411 } else if (result == DNS_R_PARTIALMATCH) { 412 result = ISC_R_NOTFOUND; 413 } 414 415 return (result); 416 } 417 418 isc_result_t 419 dns_ntatable_delete(dns_ntatable_t *ntatable, const dns_name_t *name) { 420 isc_result_t result; 421 422 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write); 423 result = deletenode(ntatable, name); 424 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write); 425 426 return (result); 427 } 428 429 bool 430 dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now, 431 const dns_name_t *name, const dns_name_t *anchor) { 432 isc_result_t result; 433 dns_fixedname_t fn; 434 dns_rbtnode_t *node; 435 dns_name_t *foundname; 436 dns_nta_t *nta = NULL; 437 bool answer = false; 438 isc_rwlocktype_t locktype = isc_rwlocktype_read; 439 440 REQUIRE(ntatable == NULL || VALID_NTATABLE(ntatable)); 441 REQUIRE(dns_name_isabsolute(name)); 442 443 if (ntatable == NULL) { 444 return (false); 445 } 446 447 foundname = dns_fixedname_initname(&fn); 448 449 relock: 450 RWLOCK(&ntatable->rwlock, locktype); 451 again: 452 node = NULL; 453 result = dns_rbt_findnode(ntatable->table, name, foundname, &node, NULL, 454 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 455 if (result == DNS_R_PARTIALMATCH) { 456 if (dns_name_issubdomain(foundname, anchor)) { 457 result = ISC_R_SUCCESS; 458 } 459 } 460 if (result == ISC_R_SUCCESS) { 461 nta = (dns_nta_t *)node->data; 462 answer = (nta->expiry > now); 463 } 464 465 /* Deal with expired NTA */ 466 if (result == ISC_R_SUCCESS && !answer) { 467 char nb[DNS_NAME_FORMATSIZE]; 468 469 if (locktype == isc_rwlocktype_read) { 470 RWUNLOCK(&ntatable->rwlock, locktype); 471 locktype = isc_rwlocktype_write; 472 goto relock; 473 } 474 475 dns_name_format(foundname, nb, sizeof(nb)); 476 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, 477 DNS_LOGMODULE_NTA, ISC_LOG_INFO, 478 "deleting expired NTA at %s", nb); 479 480 if (nta->timer != NULL) { 481 (void)isc_timer_reset(nta->timer, 482 isc_timertype_inactive, NULL, 483 NULL, true); 484 isc_timer_detach(&nta->timer); 485 } 486 487 result = deletenode(ntatable, foundname); 488 if (result != ISC_R_SUCCESS) { 489 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, 490 DNS_LOGMODULE_NTA, ISC_LOG_INFO, 491 "deleting NTA failed: %s", 492 isc_result_totext(result)); 493 } 494 goto again; 495 } 496 RWUNLOCK(&ntatable->rwlock, locktype); 497 498 return (answer); 499 } 500 501 static isc_result_t 502 putstr(isc_buffer_t **b, const char *str) { 503 isc_result_t result; 504 505 result = isc_buffer_reserve(b, strlen(str)); 506 if (result != ISC_R_SUCCESS) { 507 return (result); 508 } 509 510 isc_buffer_putstr(*b, str); 511 return (ISC_R_SUCCESS); 512 } 513 514 isc_result_t 515 dns_ntatable_totext(dns_ntatable_t *ntatable, const char *view, 516 isc_buffer_t **buf) { 517 isc_result_t result; 518 dns_rbtnode_t *node; 519 dns_rbtnodechain_t chain; 520 bool first = true; 521 isc_stdtime_t now; 522 523 REQUIRE(VALID_NTATABLE(ntatable)); 524 525 isc_stdtime_get(&now); 526 527 RWLOCK(&ntatable->rwlock, isc_rwlocktype_read); 528 dns_rbtnodechain_init(&chain); 529 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL); 530 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 531 if (result == ISC_R_NOTFOUND) { 532 result = ISC_R_SUCCESS; 533 } 534 goto cleanup; 535 } 536 for (;;) { 537 dns_rbtnodechain_current(&chain, NULL, NULL, &node); 538 if (node->data != NULL) { 539 dns_nta_t *n = (dns_nta_t *)node->data; 540 char nbuf[DNS_NAME_FORMATSIZE]; 541 char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; 542 char obuf[DNS_NAME_FORMATSIZE + 543 ISC_FORMATHTTPTIMESTAMP_SIZE + 544 sizeof("expired: \n")]; 545 dns_fixedname_t fn; 546 dns_name_t *name; 547 isc_time_t t; 548 549 /* 550 * Skip "validate-except" entries. 551 */ 552 if (n->expiry != 0xffffffffU) { 553 name = dns_fixedname_initname(&fn); 554 dns_rbt_fullnamefromnode(node, name); 555 dns_name_format(name, nbuf, sizeof(nbuf)); 556 isc_time_set(&t, n->expiry, 0); 557 isc_time_formattimestamp(&t, tbuf, 558 sizeof(tbuf)); 559 560 snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s %s", 561 first ? "" : "\n", nbuf, 562 view != NULL ? "/" : "", 563 view != NULL ? view : "", 564 n->expiry <= now ? "expired" 565 : "expiry", 566 tbuf); 567 first = false; 568 result = putstr(buf, obuf); 569 if (result != ISC_R_SUCCESS) { 570 goto cleanup; 571 } 572 } 573 } 574 result = dns_rbtnodechain_next(&chain, NULL, NULL); 575 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 576 if (result == ISC_R_NOMORE) { 577 result = ISC_R_SUCCESS; 578 } 579 break; 580 } 581 } 582 583 cleanup: 584 dns_rbtnodechain_invalidate(&chain); 585 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read); 586 return (result); 587 } 588 589 isc_result_t 590 dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) { 591 isc_result_t result; 592 isc_buffer_t *text = NULL; 593 int len = 4096; 594 595 isc_buffer_allocate(ntatable->view->mctx, &text, len); 596 597 result = dns_ntatable_totext(ntatable, NULL, &text); 598 599 if (isc_buffer_usedlength(text) != 0) { 600 (void)putstr(&text, "\n"); 601 } else if (result == ISC_R_SUCCESS) { 602 (void)putstr(&text, "none"); 603 } else { 604 (void)putstr(&text, "could not dump NTA table: "); 605 (void)putstr(&text, isc_result_totext(result)); 606 } 607 608 fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text), 609 (char *)isc_buffer_base(text)); 610 isc_buffer_free(&text); 611 return (result); 612 } 613 614 isc_result_t 615 dns_ntatable_save(dns_ntatable_t *ntatable, FILE *fp) { 616 isc_result_t result; 617 dns_rbtnode_t *node; 618 dns_rbtnodechain_t chain; 619 isc_stdtime_t now; 620 bool written = false; 621 622 REQUIRE(VALID_NTATABLE(ntatable)); 623 624 isc_stdtime_get(&now); 625 626 RWLOCK(&ntatable->rwlock, isc_rwlocktype_read); 627 dns_rbtnodechain_init(&chain); 628 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL); 629 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 630 goto cleanup; 631 } 632 633 for (;;) { 634 dns_rbtnodechain_current(&chain, NULL, NULL, &node); 635 if (node->data != NULL) { 636 isc_buffer_t b; 637 char nbuf[DNS_NAME_FORMATSIZE + 1], tbuf[80]; 638 dns_fixedname_t fn; 639 dns_name_t *name; 640 dns_nta_t *n = (dns_nta_t *)node->data; 641 642 /* 643 * Skip this node if the expiry is already in the 644 * past, or if this is a "validate-except" entry. 645 */ 646 if (n->expiry <= now || n->expiry == 0xffffffffU) { 647 goto skip; 648 } 649 650 name = dns_fixedname_initname(&fn); 651 dns_rbt_fullnamefromnode(node, name); 652 653 isc_buffer_init(&b, nbuf, sizeof(nbuf)); 654 result = dns_name_totext(name, false, &b); 655 if (result != ISC_R_SUCCESS) { 656 goto skip; 657 } 658 659 /* Zero terminate. */ 660 isc_buffer_putuint8(&b, 0); 661 662 isc_buffer_init(&b, tbuf, sizeof(tbuf)); 663 dns_time32_totext(n->expiry, &b); 664 665 /* Zero terminate. */ 666 isc_buffer_putuint8(&b, 0); 667 668 fprintf(fp, "%s %s %s\n", nbuf, 669 n->forced ? "forced" : "regular", tbuf); 670 written = true; 671 } 672 skip: 673 result = dns_rbtnodechain_next(&chain, NULL, NULL); 674 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 675 if (result == ISC_R_NOMORE) { 676 result = ISC_R_SUCCESS; 677 } 678 break; 679 } 680 } 681 682 cleanup: 683 dns_rbtnodechain_invalidate(&chain); 684 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read); 685 686 if (result != ISC_R_SUCCESS) { 687 return (result); 688 } else { 689 return (written ? ISC_R_SUCCESS : ISC_R_NOTFOUND); 690 } 691 } 692 693 void 694 dns_ntatable_shutdown(dns_ntatable_t *ntatable) { 695 isc_result_t result; 696 dns_rbtnode_t *node; 697 dns_rbtnodechain_t chain; 698 699 REQUIRE(VALID_NTATABLE(ntatable)); 700 701 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write); 702 ntatable->shuttingdown = true; 703 704 dns_rbtnodechain_init(&chain); 705 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL); 706 while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { 707 dns_rbtnodechain_current(&chain, NULL, NULL, &node); 708 if (node->data != NULL) { 709 dns_nta_t *nta = (dns_nta_t *)node->data; 710 if (nta->timer != NULL) { 711 (void)isc_timer_reset(nta->timer, 712 isc_timertype_inactive, 713 NULL, NULL, true); 714 } 715 } 716 result = dns_rbtnodechain_next(&chain, NULL, NULL); 717 } 718 719 dns_rbtnodechain_invalidate(&chain); 720 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write); 721 } 722