Coverage Report

Created: 2026-06-07 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/nta.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <inttypes.h>
17
#include <stdbool.h>
18
19
#include <isc/async.h>
20
#include <isc/atomic.h>
21
#include <isc/buffer.h>
22
#include <isc/log.h>
23
#include <isc/loop.h>
24
#include <isc/mem.h>
25
#include <isc/refcount.h>
26
#include <isc/result.h>
27
#include <isc/string.h>
28
#include <isc/time.h>
29
#include <isc/timer.h>
30
#include <isc/urcu.h>
31
#include <isc/util.h>
32
33
#include <dns/db.h>
34
#include <dns/fixedname.h>
35
#include <dns/name.h>
36
#include <dns/nta.h>
37
#include <dns/qp.h>
38
#include <dns/rdataset.h>
39
#include <dns/resolver.h>
40
#include <dns/time.h>
41
42
struct dns_ntatable {
43
  unsigned int magic;
44
  isc_mem_t *mctx;
45
  dns_view_t *view;
46
  isc_refcount_t references;
47
  dns_qpmulti_t *table;
48
};
49
50
struct dns__nta {
51
  unsigned int magic;
52
  isc_mem_t *mctx;
53
  isc_loop_t *loop;
54
  isc_refcount_t references;
55
  dns_ntatable_t *ntatable;
56
  bool forced;
57
  isc_timer_t *timer;
58
  dns_fetch_t *fetch;
59
  dns_rdataset_t rdataset;
60
  dns_rdataset_t sigrdataset;
61
  dns_name_t name;
62
  isc_stdtime_t expiry;
63
};
64
65
0
#define NTA_MAGIC     ISC_MAGIC('N', 'T', 'A', 'n')
66
#define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC)
67
68
static void
69
dns__nta_shutdown(dns__nta_t *nta);
70
71
static void
72
qp_attach(void *uctx, void *pval, uint32_t ival);
73
static void
74
qp_detach(void *uctx, void *pval, uint32_t ival);
75
static size_t
76
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
77
static void
78
qp_triename(void *uctx, char *buf, size_t size);
79
80
static dns_qpmethods_t qpmethods = {
81
  qp_attach,
82
  qp_detach,
83
  qp_makekey,
84
  qp_triename,
85
};
86
87
static void
88
0
dns__nta_destroy(dns__nta_t *nta) {
89
0
  REQUIRE(nta->timer == NULL);
90
91
0
  nta->magic = 0;
92
0
  dns_ntatable_detach(&nta->ntatable);
93
0
  dns_rdataset_cleanup(&nta->rdataset);
94
0
  dns_rdataset_cleanup(&nta->sigrdataset);
95
0
  if (nta->fetch != NULL) {
96
0
    dns_resolver_cancelfetch(nta->fetch);
97
0
    dns_resolver_destroyfetch(&nta->fetch);
98
0
  }
99
0
  isc_loop_detach(&nta->loop);
100
0
  dns_name_free(&nta->name, nta->mctx);
101
0
  isc_mem_putanddetach(&nta->mctx, nta, sizeof(*nta));
102
0
}
103
104
#if DNS_NTA_TRACE
105
ISC_REFCOUNT_TRACE_IMPL(dns__nta, dns__nta_destroy);
106
#else
107
0
ISC_REFCOUNT_IMPL(dns__nta, dns__nta_destroy);
Unexecuted instantiation: dns__nta_ref
Unexecuted instantiation: dns__nta_unref
Unexecuted instantiation: dns__nta_detach
108
0
#endif
109
0
110
0
void
111
0
dns_ntatable_create(dns_view_t *view, dns_ntatable_t **ntatablep) {
112
0
  dns_ntatable_t *ntatable = NULL;
113
114
0
  REQUIRE(ntatablep != NULL && *ntatablep == NULL);
115
116
0
  ntatable = isc_mem_get(view->mctx, sizeof(*ntatable));
117
0
  *ntatable = (dns_ntatable_t){
118
0
    .magic = NTATABLE_MAGIC,
119
0
    .mctx = isc_mem_ref(view->mctx),
120
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
121
0
  };
122
123
0
  dns_view_weakattach(view, &ntatable->view);
124
125
0
  dns_qpmulti_create(view->mctx, &qpmethods, view, &ntatable->table);
126
127
0
  *ntatablep = ntatable;
128
0
}
129
130
static void
131
0
dns__ntatable_destroy(dns_ntatable_t *ntatable) {
132
0
  ntatable->magic = 0;
133
0
  INSIST(ntatable->table == NULL);
134
0
  INSIST(ntatable->view == NULL);
135
0
  isc_mem_putanddetach(&ntatable->mctx, ntatable, sizeof(*ntatable));
136
0
}
137
138
#if DNS_NTA_TRACE
139
ISC_REFCOUNT_TRACE_IMPL(dns_ntatable, dns__ntatable_destroy);
140
#else
141
0
ISC_REFCOUNT_IMPL(dns_ntatable, dns__ntatable_destroy);
Unexecuted instantiation: dns_ntatable_ref
Unexecuted instantiation: dns_ntatable_unref
Unexecuted instantiation: dns_ntatable_detach
142
0
#endif
143
0
144
0
static void
145
0
fetch_done(void *arg) {
146
0
  dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
147
0
  dns__nta_t *nta = resp->arg;
148
0
  isc_result_t eresult = resp->result;
149
0
  dns_ntatable_t *ntatable = nta->ntatable;
150
0
  isc_stdtime_t now = isc_stdtime_now();
151
0
  isc_stdtime_t expiry;
152
153
0
  rcu_read_lock();
154
0
  dns_view_t *view = rcu_dereference(ntatable->view);
155
156
0
  dns_rdataset_cleanup(&nta->rdataset);
157
0
  dns_rdataset_cleanup(&nta->sigrdataset);
158
0
  if (nta->fetch == resp->fetch) {
159
0
    nta->fetch = NULL;
160
0
  }
161
0
  dns_resolver_destroyfetch(&resp->fetch);
162
163
0
  if (resp->node != NULL) {
164
0
    dns_db_detachnode(&resp->node);
165
0
  }
166
0
  if (resp->cache != NULL) {
167
0
    dns_db_detach(&resp->cache);
168
0
  }
169
170
0
  dns_resolver_freefresp(&resp);
171
172
0
  expiry = CMM_LOAD_SHARED(nta->expiry);
173
174
0
  switch (eresult) {
175
0
  case ISC_R_SUCCESS:
176
0
  case DNS_R_NCACHENXDOMAIN:
177
0
  case DNS_R_NXDOMAIN:
178
0
  case DNS_R_NCACHENXRRSET:
179
0
  case DNS_R_NXRRSET:
180
0
    if (expiry > now) {
181
0
      CMM_STORE_SHARED(nta->expiry, now);
182
0
      expiry = now;
183
0
    }
184
0
    break;
185
0
  default:
186
0
    break;
187
0
  }
188
189
  /*
190
   * If we're expiring before the next recheck, we might
191
   * as well stop the timer now.
192
   */
193
0
  if (nta->timer != NULL &&
194
0
      (view == NULL || expiry - now < view->nta_recheck))
195
0
  {
196
0
    isc_timer_stop(nta->timer);
197
0
  }
198
199
0
  rcu_read_unlock();
200
0
  dns__nta_detach(&nta); /* for dns_resolver_createfetch() */
201
0
}
202
203
static void
204
0
checkbogus(void *arg) {
205
0
  dns__nta_t *nta = arg;
206
0
  dns_ntatable_t *ntatable = nta->ntatable;
207
0
  dns_resolver_t *resolver = NULL;
208
0
  isc_result_t result;
209
210
0
  if (nta->fetch != NULL) {
211
0
    dns_resolver_cancelfetch(nta->fetch);
212
0
    nta->fetch = NULL;
213
0
  }
214
0
  dns_rdataset_cleanup(&nta->rdataset);
215
0
  dns_rdataset_cleanup(&nta->sigrdataset);
216
217
0
  rcu_read_lock();
218
0
  dns_view_t *view = rcu_dereference(ntatable->view);
219
0
  if (view == NULL) {
220
0
    isc_timer_stop(nta->timer);
221
0
    rcu_read_unlock();
222
0
    return;
223
0
  }
224
225
0
  result = dns_view_getresolver(view, &resolver);
226
0
  if (result != ISC_R_SUCCESS) {
227
0
    rcu_read_unlock();
228
0
    return;
229
0
  }
230
231
0
  dns__nta_ref(nta); /* for dns_resolver_createfetch */
232
0
  result = dns_resolver_createfetch(
233
0
    resolver, &nta->name, dns_rdatatype_nsec, NULL, NULL, NULL,
234
0
    NULL, 0, DNS_FETCHOPT_NONTA, 0, NULL, NULL, NULL, nta->loop,
235
0
    fetch_done, nta, NULL, &nta->rdataset, &nta->sigrdataset,
236
0
    &nta->fetch);
237
0
  if (result != ISC_R_SUCCESS) {
238
0
    dns__nta_detach(&nta); /* for dns_resolver_createfetch() */
239
0
  }
240
0
  dns_resolver_detach(&resolver);
241
0
  rcu_read_unlock();
242
0
}
243
244
static void
245
0
settimer(dns_view_t *view, dns__nta_t *nta, uint32_t lifetime) {
246
0
  REQUIRE(VALID_NTA(nta));
247
248
0
  if (view->nta_recheck == 0 || lifetime <= view->nta_recheck) {
249
0
    return;
250
0
  }
251
252
0
  isc_interval_t interval;
253
0
  isc_interval_set(&interval, view->nta_recheck, 0);
254
255
0
  isc_timer_create(nta->loop, checkbogus, nta, &nta->timer);
256
0
  isc_timer_start(nta->timer, isc_timertype_ticker, &interval);
257
0
}
258
259
static void
260
nta_create(dns_ntatable_t *ntatable, const dns_name_t *name,
261
0
     dns__nta_t **target) {
262
0
  dns__nta_t *nta = NULL;
263
264
0
  REQUIRE(VALID_NTATABLE(ntatable));
265
0
  REQUIRE(target != NULL && *target == NULL);
266
267
0
  nta = isc_mem_get(ntatable->mctx, sizeof(dns__nta_t));
268
0
  *nta = (dns__nta_t){
269
0
    .ntatable = dns_ntatable_ref(ntatable),
270
0
    .name = DNS_NAME_INITEMPTY,
271
0
    .magic = NTA_MAGIC,
272
0
  };
273
0
  isc_mem_attach(ntatable->mctx, &nta->mctx);
274
0
  isc_loop_attach(isc_loop(), &nta->loop);
275
276
0
  dns_rdataset_init(&nta->rdataset);
277
0
  dns_rdataset_init(&nta->sigrdataset);
278
279
0
  isc_refcount_init(&nta->references, 1);
280
281
0
  dns_name_dup(name, nta->mctx, &nta->name);
282
283
0
  *target = nta;
284
0
}
285
286
isc_result_t
287
dns_ntatable_add(dns_ntatable_t *ntatable, const dns_name_t *name, bool force,
288
0
     isc_stdtime_t now, uint32_t lifetime) {
289
0
  isc_result_t result = ISC_R_SUCCESS;
290
0
  dns__nta_t *nta = NULL, *old_nta = NULL;
291
0
  dns_qp_t *qp = NULL;
292
293
0
  REQUIRE(VALID_NTATABLE(ntatable));
294
295
0
  rcu_read_lock();
296
0
  dns_view_t *view = rcu_dereference(ntatable->view);
297
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
298
0
  if (view == NULL || table == NULL) {
299
0
    rcu_read_unlock();
300
0
    return ISC_R_SUCCESS;
301
0
  }
302
303
0
  dns_qpmulti_write(table, &qp);
304
0
  nta_create(ntatable, name, &nta);
305
0
  nta->forced = force;
306
0
  result = dns_qp_insert(qp, nta, 0);
307
0
  switch (result) {
308
0
  case ISC_R_EXISTS:
309
0
    result = dns_qp_deletename(qp, name, DNS_DBNAMESPACE_NORMAL,
310
0
             (void *)&old_nta, NULL);
311
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
312
313
0
    dns__nta_shutdown(old_nta);
314
0
    dns__nta_detach(&old_nta);
315
316
0
    result = dns_qp_insert(qp, nta, 0);
317
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
318
319
0
    FALLTHROUGH;
320
0
  case ISC_R_SUCCESS:
321
0
    CMM_STORE_SHARED(nta->expiry, now + lifetime);
322
0
    if (!force) {
323
0
      settimer(view, nta, lifetime);
324
0
    }
325
0
    break;
326
0
  default:
327
0
    UNREACHABLE();
328
0
  }
329
330
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
331
0
  dns_qpmulti_commit(table, &qp);
332
333
0
  rcu_read_unlock();
334
335
0
  return result;
336
0
}
337
338
isc_result_t
339
0
dns_ntatable_delete(dns_ntatable_t *ntatable, const dns_name_t *name) {
340
0
  isc_result_t result;
341
0
  dns_qp_t *qp = NULL;
342
0
  void *pval = NULL;
343
344
0
  REQUIRE(VALID_NTATABLE(ntatable));
345
0
  REQUIRE(name != NULL);
346
347
0
  rcu_read_lock();
348
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
349
0
  if (table == NULL) {
350
0
    rcu_read_unlock();
351
0
    return ISC_R_SUCCESS;
352
0
  }
353
354
0
  dns_qpmulti_write(table, &qp);
355
0
  result = dns_qp_deletename(qp, name, DNS_DBNAMESPACE_NORMAL, &pval,
356
0
           NULL);
357
0
  if (result == ISC_R_SUCCESS) {
358
0
    dns__nta_t *n = pval;
359
0
    dns__nta_shutdown(n);
360
0
    dns__nta_detach(&n);
361
0
  }
362
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
363
0
  dns_qpmulti_commit(table, &qp);
364
365
0
  rcu_read_unlock();
366
367
0
  return result;
368
0
}
369
370
static void
371
0
delete_expired(void *arg) {
372
0
  dns__nta_t *nta = arg;
373
0
  dns_ntatable_t *ntatable = nta->ntatable;
374
0
  isc_result_t result;
375
0
  dns_qp_t *qp = NULL;
376
0
  void *pval = NULL;
377
378
0
  REQUIRE(VALID_NTATABLE(ntatable));
379
380
0
  rcu_read_lock();
381
0
  dns_view_t *view = rcu_dereference(ntatable->view);
382
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
383
0
  if (view == NULL || table == NULL) {
384
0
    goto unlock;
385
0
  }
386
387
0
  dns_qpmulti_write(table, &qp);
388
0
  result = dns_qp_getname(qp, &nta->name, DNS_DBNAMESPACE_NORMAL, &pval,
389
0
        NULL);
390
0
  if (result == ISC_R_SUCCESS && nta == pval) {
391
0
    char nb[DNS_NAME_FORMATSIZE];
392
0
    dns_name_format(&nta->name, nb, sizeof(nb));
393
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_NTA,
394
0
            ISC_LOG_INFO, "deleting expired NTA at %s", nb);
395
396
0
    result = dns_qp_deletename(qp, &nta->name,
397
0
             DNS_DBNAMESPACE_NORMAL, NULL, NULL);
398
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
399
0
    dns__nta_shutdown(nta);
400
0
    dns__nta_unref(nta);
401
0
  }
402
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
403
0
  dns_qpmulti_commit(table, &qp);
404
0
unlock:
405
0
  rcu_read_unlock();
406
0
  dns__nta_detach(&nta);
407
0
  dns_ntatable_detach(&ntatable);
408
0
}
409
410
bool
411
dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
412
0
         const dns_name_t *name, const dns_name_t *anchor) {
413
0
  isc_result_t result;
414
0
  dns__nta_t *nta = NULL;
415
0
  bool answer = false;
416
0
  dns_qpread_t qpr;
417
0
  void *pval = NULL;
418
419
0
  REQUIRE(VALID_NTATABLE(ntatable));
420
0
  REQUIRE(dns_name_isabsolute(name));
421
422
0
  rcu_read_lock();
423
0
  dns_view_t *view = rcu_dereference(ntatable->view);
424
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
425
0
  if (view == NULL || table == NULL) {
426
0
    goto unlock;
427
0
  }
428
429
0
  dns_qpmulti_query(table, &qpr);
430
0
  result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NORMAL, NULL, NULL,
431
0
             &pval, NULL);
432
0
  nta = pval;
433
434
0
  switch (result) {
435
0
  case ISC_R_SUCCESS:
436
    /* Exact match */
437
0
    break;
438
0
  case DNS_R_PARTIALMATCH:
439
    /*
440
     * Found a NTA that's an ancestor of 'name'; we
441
     * now have to make sure 'anchor' isn't below it.
442
     */
443
0
    if (!dns_name_issubdomain(&nta->name, anchor)) {
444
0
      goto done;
445
0
    }
446
    /* Ancestor match */
447
0
    break;
448
0
  default:
449
    /* Found nothing */
450
0
    goto done;
451
0
  }
452
453
0
  if (CMM_LOAD_SHARED(nta->expiry) <= now) {
454
    /* NTA is expired */
455
0
    dns__nta_ref(nta);
456
0
    dns_ntatable_ref(nta->ntatable);
457
0
    isc_async_run(nta->loop, delete_expired, nta);
458
0
    goto done;
459
0
  }
460
461
0
  answer = true;
462
0
done:
463
0
  dns_qpread_destroy(table, &qpr);
464
0
unlock:
465
0
  rcu_read_unlock();
466
467
0
  return answer;
468
0
}
469
470
static isc_result_t
471
0
putstr(isc_buffer_t *b, const char *str) {
472
0
  RETERR(isc_buffer_reserve(b, strlen(str)));
473
474
0
  isc_buffer_putstr(b, str);
475
0
  return ISC_R_SUCCESS;
476
0
}
477
478
isc_result_t
479
dns_ntatable_totext(dns_ntatable_t *ntatable, const char *view,
480
0
        isc_buffer_t *buf) {
481
0
  isc_result_t result = ISC_R_SUCCESS;
482
0
  isc_stdtime_t now = isc_stdtime_now();
483
0
  dns_qpread_t qpr;
484
0
  dns_qpiter_t iter;
485
0
  bool first = true;
486
0
  void *pval = NULL;
487
488
0
  REQUIRE(VALID_NTATABLE(ntatable));
489
490
0
  rcu_read_lock();
491
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
492
0
  if (table == NULL) {
493
0
    rcu_read_unlock();
494
0
    return ISC_R_SUCCESS;
495
0
  }
496
497
0
  dns_qpmulti_query(table, &qpr);
498
0
  dns_qpiter_init(&qpr, &iter);
499
500
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
501
0
    dns__nta_t *n = pval;
502
0
    char nbuf[DNS_NAME_FORMATSIZE];
503
0
    char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
504
0
    char obuf[DNS_NAME_FORMATSIZE + ISC_FORMATHTTPTIMESTAMP_SIZE +
505
0
        sizeof("expired:  \n")];
506
0
    isc_time_t t;
507
0
    isc_stdtime_t expiry = CMM_LOAD_SHARED(n->expiry);
508
509
0
    dns_name_format(&n->name, nbuf, sizeof(nbuf));
510
511
0
    if (expiry != 0xffffffffU) {
512
      /* Normal NTA entries */
513
0
      isc_time_set(&t, expiry, 0);
514
0
      isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
515
516
0
      snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s %s",
517
0
         first ? "" : "\n", nbuf,
518
0
         view != NULL ? "/" : "",
519
0
         view != NULL ? view : "",
520
0
         expiry <= now ? "expired" : "expiry", tbuf);
521
0
    } else {
522
      /* "validate-except" entries */
523
0
      snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s",
524
0
         first ? "" : "\n", nbuf,
525
0
         view != NULL ? "/" : "",
526
0
         view != NULL ? view : "", "permanent");
527
0
    }
528
529
0
    first = false;
530
0
    CHECK(putstr(buf, obuf));
531
0
  }
532
533
0
cleanup:
534
0
  dns_qpread_destroy(table, &qpr);
535
0
  rcu_read_unlock();
536
0
  return result;
537
0
}
538
539
isc_result_t
540
0
dns_ntatable_save(dns_ntatable_t *ntatable, FILE *fp) {
541
0
  isc_result_t result = ISC_R_SUCCESS;
542
0
  isc_stdtime_t now = isc_stdtime_now();
543
0
  dns_qpread_t qpr;
544
0
  dns_qpiter_t iter;
545
0
  bool written = false;
546
0
  void *pval = NULL;
547
548
0
  REQUIRE(VALID_NTATABLE(ntatable));
549
550
0
  rcu_read_lock();
551
0
  dns_qpmulti_t *table = rcu_dereference(ntatable->table);
552
0
  if (table == NULL) {
553
0
    rcu_read_unlock();
554
0
    return ISC_R_SUCCESS;
555
0
  }
556
557
0
  dns_qpmulti_query(table, &qpr);
558
0
  dns_qpiter_init(&qpr, &iter);
559
560
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
561
0
    dns__nta_t *n = pval;
562
0
    isc_buffer_t b;
563
0
    char nbuf[DNS_NAME_FORMATSIZE + 1], tbuf[80];
564
0
    isc_stdtime_t expiry = CMM_LOAD_SHARED(n->expiry);
565
566
    /*
567
     * Skip this node if the expiry is already in the
568
     * past, or if this is a "validate-except" entry.
569
     */
570
0
    if (expiry <= now || expiry == 0xffffffffU) {
571
0
      continue;
572
0
    }
573
574
0
    isc_buffer_init(&b, nbuf, sizeof(nbuf));
575
0
    result = dns_name_totext(&n->name, 0, &b);
576
0
    if (result != ISC_R_SUCCESS) {
577
0
      continue;
578
0
    }
579
580
    /* Zero terminate */
581
0
    isc_buffer_putuint8(&b, 0);
582
583
0
    isc_buffer_init(&b, tbuf, sizeof(tbuf));
584
0
    dns_time32_totext(expiry, &b);
585
586
    /* Zero terminate */
587
0
    isc_buffer_putuint8(&b, 0);
588
589
0
    fprintf(fp, "%s %s %s\n", nbuf,
590
0
      n->forced ? "forced" : "regular", tbuf);
591
0
    written = true;
592
0
  }
593
594
0
  dns_qpread_destroy(table, &qpr);
595
0
  rcu_read_unlock();
596
597
0
  if (result == ISC_R_SUCCESS && !written) {
598
0
    result = ISC_R_NOTFOUND;
599
0
  }
600
601
0
  return result;
602
0
}
603
604
static void
605
0
dns__nta_shutdown_cb(void *arg) {
606
0
  dns__nta_t *nta = arg;
607
608
0
  REQUIRE(VALID_NTA(nta));
609
610
0
  if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
611
0
    char nb[DNS_NAME_FORMATSIZE];
612
0
    dns_name_format(&nta->name, nb, sizeof(nb));
613
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_NTA,
614
0
            ISC_LOG_DEBUG(3), "shutting down NTA %p at %s",
615
0
            nta, nb);
616
0
  }
617
0
  if (nta->timer) {
618
0
    isc_timer_stop(nta->timer);
619
0
    isc_timer_destroy(&nta->timer);
620
0
  }
621
622
0
  dns__nta_detach(&nta);
623
0
}
624
625
static void
626
0
dns__nta_shutdown(dns__nta_t *nta) {
627
0
  REQUIRE(VALID_NTA(nta));
628
629
0
  dns__nta_ref(nta);
630
0
  isc_async_run(nta->loop, dns__nta_shutdown_cb, nta);
631
0
}
632
633
void
634
0
dns_ntatable_shutdown(dns_ntatable_t *ntatable) {
635
0
  REQUIRE(VALID_NTATABLE(ntatable));
636
637
0
  dns_view_t *view = rcu_xchg_pointer(&ntatable->view, NULL);
638
0
  dns_qpmulti_t *table = rcu_xchg_pointer(&ntatable->table, NULL);
639
640
0
  synchronize_rcu();
641
642
0
  dns_qpread_t qpr;
643
0
  dns_qpiter_t iter;
644
0
  void *pval = NULL;
645
646
0
  dns_qpmulti_query(table, &qpr);
647
648
0
  dns_qpiter_init(&qpr, &iter);
649
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
650
0
    dns__nta_t *nta = pval;
651
652
0
    dns__nta_shutdown(nta);
653
0
    dns__nta_detach(&nta);
654
0
  }
655
656
0
  dns_qpread_destroy(table, &qpr);
657
0
  dns_view_weakdetach(&view);
658
0
  dns_qpmulti_destroy(&table);
659
0
}
660
661
static void
662
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
663
0
    uint32_t ival ISC_ATTR_UNUSED) {
664
0
  dns__nta_t *nta = pval;
665
0
  dns__nta_ref(nta);
666
0
}
667
668
static void
669
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
670
0
    uint32_t ival ISC_ATTR_UNUSED) {
671
0
  dns__nta_t *nta = pval;
672
0
  dns__nta_detach(&nta);
673
0
}
674
675
static size_t
676
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
677
0
     uint32_t ival ISC_ATTR_UNUSED) {
678
0
  dns__nta_t *nta = pval;
679
0
  return dns_qpkey_fromname(key, &nta->name, DNS_DBNAMESPACE_NORMAL);
680
0
}
681
682
static void
683
0
qp_triename(void *uctx, char *buf, size_t size) {
684
0
  dns_view_t *view = uctx;
685
0
  snprintf(buf, size, "view %s forwarder table", view->name);
686
0
}