"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/dns/nta.c" (4 Sep 2020, 17385 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "nta.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.16.6_vs_9.16.7.

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