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