00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include <isc/buffer.h>
00022 #include <isc/log.h>
00023 #include <isc/mem.h>
00024 #include <isc/print.h>
00025 #include <isc/rwlock.h>
00026 #include <isc/string.h>
00027 #include <isc/task.h>
00028 #include <isc/time.h>
00029 #include <isc/timer.h>
00030 #include <isc/util.h>
00031
00032 #include <dns/db.h>
00033 #include <dns/log.h>
00034 #include <dns/nta.h>
00035 #include <dns/fixedname.h>
00036 #include <dns/name.h>
00037 #include <dns/rbt.h>
00038 #include <dns/rdataset.h>
00039 #include <dns/resolver.h>
00040 #include <dns/result.h>
00041 #include <dns/time.h>
00042
00043 struct dns_nta {
00044 unsigned int magic;
00045 isc_refcount_t refcount;
00046 dns_ntatable_t *ntatable;
00047 isc_boolean_t forced;
00048 isc_timer_t *timer;
00049 dns_fetch_t *fetch;
00050 dns_rdataset_t rdataset;
00051 dns_rdataset_t sigrdataset;
00052 dns_fixedname_t fn;
00053 dns_name_t *name;
00054 isc_stdtime_t expiry;
00055 };
00056
00057 #define NTA_MAGIC ISC_MAGIC('N', 'T', 'A', 'n')
00058 #define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC)
00059
00060
00061
00062
00063
00064 static void
00065 nta_ref(dns_nta_t *nta) {
00066 isc_refcount_increment(&nta->refcount, NULL);
00067 }
00068
00069 static void
00070 nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
00071 unsigned int refs;
00072 dns_nta_t *nta = *ntap;
00073
00074 REQUIRE(VALID_NTA(nta));
00075
00076 *ntap = NULL;
00077 isc_refcount_decrement(&nta->refcount, &refs);
00078 if (refs == 0) {
00079 nta->magic = 0;
00080 if (nta->timer != NULL) {
00081 (void) isc_timer_reset(nta->timer,
00082 isc_timertype_inactive,
00083 NULL, NULL, ISC_TRUE);
00084 isc_timer_detach(&nta->timer);
00085 }
00086 isc_refcount_destroy(&nta->refcount);
00087 if (dns_rdataset_isassociated(&nta->rdataset))
00088 dns_rdataset_disassociate(&nta->rdataset);
00089 if (dns_rdataset_isassociated(&nta->sigrdataset))
00090 dns_rdataset_disassociate(&nta->sigrdataset);
00091 if (nta->fetch != NULL) {
00092 dns_resolver_cancelfetch(nta->fetch);
00093 dns_resolver_destroyfetch(&nta->fetch);
00094 }
00095 isc_mem_put(mctx, nta, sizeof(dns_nta_t));
00096 }
00097 }
00098
00099 static void
00100 free_nta(void *data, void *arg) {
00101 dns_nta_t *nta = (dns_nta_t *) data;
00102 isc_mem_t *mctx = (isc_mem_t *) arg;
00103
00104 nta_detach(mctx, &nta);
00105 }
00106
00107 isc_result_t
00108 dns_ntatable_create(dns_view_t *view,
00109 isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
00110 dns_ntatable_t **ntatablep)
00111 {
00112 dns_ntatable_t *ntatable;
00113 isc_result_t result;
00114
00115 REQUIRE(ntatablep != NULL && *ntatablep == NULL);
00116
00117 ntatable = isc_mem_get(view->mctx, sizeof(*ntatable));
00118 if (ntatable == NULL)
00119 return (ISC_R_NOMEMORY);
00120
00121 ntatable->task = NULL;
00122 result = isc_task_create(taskmgr, 0, &ntatable->task);
00123 if (result != ISC_R_SUCCESS)
00124 goto cleanup_ntatable;
00125 isc_task_setname(ntatable->task, "ntatable", ntatable);
00126
00127 ntatable->table = NULL;
00128 result = dns_rbt_create(view->mctx, free_nta, view->mctx,
00129 &ntatable->table);
00130 if (result != ISC_R_SUCCESS)
00131 goto cleanup_task;
00132
00133 result = isc_rwlock_init(&ntatable->rwlock, 0, 0);
00134 if (result != ISC_R_SUCCESS)
00135 goto cleanup_rbt;
00136
00137 ntatable->timermgr = timermgr;
00138 ntatable->taskmgr = taskmgr;
00139
00140 ntatable->view = view;
00141 ntatable->references = 1;
00142
00143 ntatable->magic = NTATABLE_MAGIC;
00144 *ntatablep = ntatable;
00145
00146 return (ISC_R_SUCCESS);
00147
00148 cleanup_rbt:
00149 dns_rbt_destroy(&ntatable->table);
00150
00151 cleanup_task:
00152 isc_task_detach(&ntatable->task);
00153
00154 cleanup_ntatable:
00155 isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable));
00156
00157 return (result);
00158 }
00159
00160 void
00161 dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp) {
00162 REQUIRE(VALID_NTATABLE(source));
00163 REQUIRE(targetp != NULL && *targetp == NULL);
00164
00165 RWLOCK(&source->rwlock, isc_rwlocktype_write);
00166
00167 INSIST(source->references > 0);
00168 source->references++;
00169 INSIST(source->references != 0);
00170
00171 RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
00172
00173 *targetp = source;
00174 }
00175
00176 void
00177 dns_ntatable_detach(dns_ntatable_t **ntatablep) {
00178 isc_boolean_t destroy = ISC_FALSE;
00179 dns_ntatable_t *ntatable;
00180
00181 REQUIRE(ntatablep != NULL && VALID_NTATABLE(*ntatablep));
00182
00183 ntatable = *ntatablep;
00184 *ntatablep = NULL;
00185
00186 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00187 INSIST(ntatable->references > 0);
00188 ntatable->references--;
00189 if (ntatable->references == 0)
00190 destroy = ISC_TRUE;
00191 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00192
00193 if (destroy) {
00194 dns_rbt_destroy(&ntatable->table);
00195 isc_rwlock_destroy(&ntatable->rwlock);
00196 if (ntatable->task != NULL)
00197 isc_task_detach(&ntatable->task);
00198 ntatable->timermgr = NULL;
00199 ntatable->taskmgr = NULL;
00200 ntatable->magic = 0;
00201 isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable));
00202 }
00203 }
00204
00205 static void
00206 fetch_done(isc_task_t *task, isc_event_t *event) {
00207 dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
00208 dns_nta_t *nta = devent->ev_arg;
00209 isc_result_t eresult = devent->result;
00210 dns_ntatable_t *ntatable = nta->ntatable;
00211 dns_view_t *view = ntatable->view;
00212 isc_stdtime_t now;
00213
00214 UNUSED(task);
00215
00216 if (dns_rdataset_isassociated(&nta->rdataset))
00217 dns_rdataset_disassociate(&nta->rdataset);
00218 if (dns_rdataset_isassociated(&nta->sigrdataset))
00219 dns_rdataset_disassociate(&nta->sigrdataset);
00220 if (nta->fetch == devent->fetch)
00221 nta->fetch = NULL;
00222 dns_resolver_destroyfetch(&devent->fetch);
00223
00224 if (devent->node != NULL)
00225 dns_db_detachnode(devent->db, &devent->node);
00226 if (devent->db != NULL)
00227 dns_db_detach(&devent->db);
00228
00229 isc_event_free(&event);
00230 isc_stdtime_get(&now);
00231
00232 switch (eresult) {
00233 case ISC_R_SUCCESS:
00234 case DNS_R_NCACHENXDOMAIN:
00235 case DNS_R_NXDOMAIN:
00236 case DNS_R_NCACHENXRRSET:
00237 case DNS_R_NXRRSET:
00238 nta->expiry = now;
00239 break;
00240 default:
00241 break;
00242 }
00243
00244
00245
00246
00247
00248 if (nta->timer != NULL && nta->expiry - now < ntatable->recheck)
00249 (void) isc_timer_reset(nta->timer, isc_timertype_inactive,
00250 NULL, NULL, ISC_TRUE);
00251 nta_detach(view->mctx, &nta);
00252 }
00253
00254 static void
00255 checkbogus(isc_task_t *task, isc_event_t *event) {
00256 dns_nta_t *nta = event->ev_arg;
00257 dns_ntatable_t *ntatable = nta->ntatable;
00258 dns_view_t *view = ntatable->view;
00259 isc_result_t result;
00260
00261 if (nta->fetch != NULL) {
00262 dns_resolver_cancelfetch(nta->fetch);
00263 nta->fetch = NULL;
00264 }
00265 if (dns_rdataset_isassociated(&nta->rdataset))
00266 dns_rdataset_disassociate(&nta->rdataset);
00267 if (dns_rdataset_isassociated(&nta->sigrdataset))
00268 dns_rdataset_disassociate(&nta->sigrdataset);
00269
00270 isc_event_free(&event);
00271
00272 nta_ref(nta);
00273 result = dns_resolver_createfetch(view->resolver, nta->name,
00274 dns_rdatatype_nsec,
00275 NULL, NULL, NULL,
00276 DNS_FETCHOPT_NONTA,
00277 task, fetch_done, nta,
00278 &nta->rdataset,
00279 &nta->sigrdataset,
00280 &nta->fetch);
00281 if (result != ISC_R_SUCCESS)
00282 nta_detach(view->mctx, &nta);
00283 }
00284
00285 static isc_result_t
00286 settimer(dns_ntatable_t *ntatable, dns_nta_t *nta, isc_uint32_t lifetime) {
00287 isc_result_t result;
00288 isc_interval_t interval;
00289 dns_view_t *view;
00290
00291 REQUIRE(VALID_NTATABLE(ntatable));
00292 REQUIRE(VALID_NTA(nta));
00293
00294 if (ntatable->timermgr == NULL)
00295 return (ISC_R_SUCCESS);
00296
00297 view = ntatable->view;
00298 if (view->nta_recheck == 0 || lifetime <= view->nta_recheck)
00299 return (ISC_R_SUCCESS);
00300
00301 isc_interval_set(&interval, view->nta_recheck, 0);
00302 result = isc_timer_create(ntatable->timermgr, isc_timertype_ticker,
00303 NULL, &interval, ntatable->task,
00304 checkbogus, nta, &nta->timer);
00305 return (result);
00306 }
00307
00308 static isc_result_t
00309 nta_create(dns_ntatable_t *ntatable, dns_name_t *name, dns_nta_t **target) {
00310 isc_result_t result;
00311 dns_nta_t *nta = NULL;
00312 dns_view_t *view;
00313
00314 REQUIRE(VALID_NTATABLE(ntatable));
00315 REQUIRE(target != NULL && *target == NULL);
00316
00317 view = ntatable->view;
00318
00319 nta = isc_mem_get(view->mctx, sizeof(dns_nta_t));
00320 if (nta == NULL)
00321 return (ISC_R_NOMEMORY);
00322
00323 nta->ntatable = ntatable;
00324 nta->expiry = 0;
00325 nta->timer = NULL;
00326 nta->fetch = NULL;
00327 dns_rdataset_init(&nta->rdataset);
00328 dns_rdataset_init(&nta->sigrdataset);
00329
00330 result = isc_refcount_init(&nta->refcount, 1);
00331 if (result != ISC_R_SUCCESS) {
00332 isc_mem_put(view->mctx, nta, sizeof(dns_nta_t));
00333 return (result);
00334 }
00335
00336 dns_fixedname_init(&nta->fn);
00337 nta->name = dns_fixedname_name(&nta->fn);
00338 dns_name_copy(name, nta->name, NULL);
00339
00340 nta->magic = NTA_MAGIC;
00341
00342 *target = nta;
00343 return (ISC_R_SUCCESS);
00344 }
00345
00346 isc_result_t
00347 dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
00348 isc_boolean_t force, isc_stdtime_t now,
00349 isc_uint32_t lifetime)
00350 {
00351 isc_result_t result;
00352 dns_nta_t *nta = NULL;
00353 dns_rbtnode_t *node;
00354 dns_view_t *view;
00355
00356 REQUIRE(VALID_NTATABLE(ntatable));
00357
00358 view = ntatable->view;
00359
00360 result = nta_create(ntatable, name, &nta);
00361 if (result != ISC_R_SUCCESS)
00362 return (result);
00363
00364 nta->expiry = now + lifetime;
00365 nta->forced = force;
00366
00367 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00368
00369 node = NULL;
00370 result = dns_rbt_addnode(ntatable->table, name, &node);
00371 if (result == ISC_R_SUCCESS) {
00372 if (!force)
00373 (void)settimer(ntatable, nta, lifetime);
00374 node->data = nta;
00375 nta = NULL;
00376 } else if (result == ISC_R_EXISTS) {
00377 dns_nta_t *n = node->data;
00378 if (n == NULL) {
00379 if (!force)
00380 (void)settimer(ntatable, nta, lifetime);
00381 node->data = nta;
00382 nta = NULL;
00383 } else {
00384 n->expiry = nta->expiry;
00385 nta_detach(view->mctx, &nta);
00386 }
00387 result = ISC_R_SUCCESS;
00388 }
00389
00390 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00391
00392 if (nta != NULL)
00393 nta_detach(view->mctx, &nta);
00394
00395 return (result);
00396 }
00397
00398
00399
00400
00401 static isc_result_t
00402 delete(dns_ntatable_t *ntatable, dns_name_t *name) {
00403 isc_result_t result;
00404 dns_rbtnode_t *node = NULL;
00405
00406 REQUIRE(VALID_NTATABLE(ntatable));
00407 REQUIRE(name != NULL);
00408
00409 result = dns_rbt_findnode(ntatable->table, name, NULL, &node, NULL,
00410 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
00411 if (result == ISC_R_SUCCESS) {
00412 if (node->data != NULL)
00413 result = dns_rbt_deletenode(ntatable->table,
00414 node, ISC_FALSE);
00415 else
00416 result = ISC_R_NOTFOUND;
00417 } else if (result == DNS_R_PARTIALMATCH)
00418 result = ISC_R_NOTFOUND;
00419
00420 return (result);
00421 }
00422
00423 isc_result_t
00424 dns_ntatable_delete(dns_ntatable_t *ntatable, dns_name_t *name) {
00425 isc_result_t result;
00426
00427 RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00428 result = delete(ntatable, name);
00429 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
00430
00431 return (result);
00432 }
00433
00434 isc_boolean_t
00435 dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
00436 dns_name_t *name, dns_name_t *anchor)
00437 {
00438 isc_result_t result;
00439 dns_fixedname_t fn;
00440 dns_rbtnode_t *node;
00441 dns_name_t *foundname;
00442 dns_nta_t *nta = NULL;
00443 isc_boolean_t answer = ISC_FALSE;
00444 isc_rwlocktype_t locktype = isc_rwlocktype_read;
00445
00446 REQUIRE(ntatable == NULL || VALID_NTATABLE(ntatable));
00447 REQUIRE(dns_name_isabsolute(name));
00448
00449 if (ntatable == NULL)
00450 return (ISC_FALSE);
00451
00452 dns_fixedname_init(&fn);
00453 foundname = dns_fixedname_name(&fn);
00454
00455 relock:
00456 RWLOCK(&ntatable->rwlock, locktype);
00457 again:
00458 node = NULL;
00459 result = dns_rbt_findnode(ntatable->table, name, foundname, &node, NULL,
00460 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
00461 if (result == DNS_R_PARTIALMATCH) {
00462 if (dns_name_issubdomain(foundname, anchor))
00463 result = ISC_R_SUCCESS;
00464 }
00465 if (result == ISC_R_SUCCESS) {
00466 nta = (dns_nta_t *) node->data;
00467 answer = ISC_TF(nta->expiry >= now);
00468 }
00469
00470
00471 if (result == ISC_R_SUCCESS && !answer) {
00472 char nb[DNS_NAME_FORMATSIZE];
00473
00474 if (locktype == isc_rwlocktype_read) {
00475 RWUNLOCK(&ntatable->rwlock, locktype);
00476 locktype = isc_rwlocktype_write;
00477 goto relock;
00478 }
00479
00480 dns_name_format(foundname, nb, sizeof(nb));
00481 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
00482 DNS_LOGMODULE_NTA, ISC_LOG_INFO,
00483 "deleting expired NTA at %s", nb);
00484
00485 if (nta->timer != NULL) {
00486 (void) isc_timer_reset(nta->timer,
00487 isc_timertype_inactive,
00488 NULL, NULL, ISC_TRUE);
00489 isc_timer_detach(&nta->timer);
00490 }
00491
00492 result = delete(ntatable, foundname);
00493 if (result != ISC_R_SUCCESS) {
00494 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
00495 DNS_LOGMODULE_NTA, ISC_LOG_INFO,
00496 "deleting NTA failed: %s",
00497 isc_result_totext(result));
00498 }
00499 goto again;
00500 }
00501 RWUNLOCK(&ntatable->rwlock, locktype);
00502
00503 return (answer);
00504 }
00505
00506 static isc_result_t
00507 putstr(isc_buffer_t **b, const char *str) {
00508 isc_result_t result;
00509
00510 result = isc_buffer_reserve(b, strlen(str));
00511 if (result != ISC_R_SUCCESS)
00512 return (result);
00513
00514 isc_buffer_putstr(*b, str);
00515 return (ISC_R_SUCCESS);
00516 }
00517
00518 isc_result_t
00519 dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t **buf) {
00520 isc_result_t result;
00521 dns_rbtnode_t *node;
00522 dns_rbtnodechain_t chain;
00523 isc_boolean_t first = ISC_TRUE;
00524 isc_stdtime_t now;
00525
00526 REQUIRE(VALID_NTATABLE(ntatable));
00527
00528 isc_stdtime_get(&now);
00529
00530 RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00531 dns_rbtnodechain_init(&chain, ntatable->view->mctx);
00532 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
00533 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
00534 if (result == ISC_R_NOTFOUND)
00535 result = ISC_R_SUCCESS;
00536 goto cleanup;
00537 }
00538 for (;;) {
00539 dns_rbtnodechain_current(&chain, NULL, NULL, &node);
00540 if (node->data != NULL) {
00541 dns_nta_t *n = (dns_nta_t *) node->data;
00542 char nbuf[DNS_NAME_FORMATSIZE];
00543 char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
00544 char obuf[DNS_NAME_FORMATSIZE +
00545 ISC_FORMATHTTPTIMESTAMP_SIZE +
00546 sizeof("expired: \n")];
00547 dns_fixedname_t fn;
00548 dns_name_t *name;
00549 isc_time_t t;
00550
00551 dns_fixedname_init(&fn);
00552 name = dns_fixedname_name(&fn);
00553 dns_rbt_fullnamefromnode(node, name);
00554 dns_name_format(name, nbuf, sizeof(nbuf));
00555 isc_time_set(&t, n->expiry, 0);
00556 isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
00557
00558 snprintf(obuf, sizeof(obuf), "%s%s: %s %s",
00559 first ? "" : "\n", nbuf,
00560 n->expiry < now ? "expired" : "expiry",
00561 tbuf);
00562 first = ISC_FALSE;
00563 result = putstr(buf, obuf);
00564 if (result != ISC_R_SUCCESS)
00565 goto cleanup;
00566 }
00567 result = dns_rbtnodechain_next(&chain, NULL, NULL);
00568 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
00569 if (result == ISC_R_NOMORE)
00570 result = ISC_R_SUCCESS;
00571 break;
00572 }
00573 }
00574
00575 cleanup:
00576 dns_rbtnodechain_invalidate(&chain);
00577 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00578 return (result);
00579 }
00580
00581 #if 0
00582 isc_result_t
00583 dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
00584 isc_result_t result;
00585 dns_rbtnode_t *node;
00586 dns_rbtnodechain_t chain;
00587 isc_stdtime_t now;
00588
00589 REQUIRE(VALID_NTATABLE(ntatable));
00590
00591 isc_stdtime_get(&now);
00592
00593 RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00594 dns_rbtnodechain_init(&chain, ntatable->view->mctx);
00595 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
00596 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
00597 goto cleanup;
00598 for (;;) {
00599 dns_rbtnodechain_current(&chain, NULL, NULL, &node);
00600 if (node->data != NULL) {
00601 dns_nta_t *n = (dns_nta_t *) node->data;
00602 char nbuf[DNS_NAME_FORMATSIZE], tbuf[80];
00603 dns_fixedname_t fn;
00604 dns_name_t *name;
00605 isc_time_t t;
00606
00607 dns_fixedname_init(&fn);
00608 name = dns_fixedname_name(&fn);
00609 dns_rbt_fullnamefromnode(node, name);
00610 dns_name_format(name, nbuf, sizeof(nbuf));
00611 isc_time_set(&t, n->expiry, 0);
00612 isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
00613 fprintf(fp, "%s: %s %s\n", nbuf,
00614 n->expiry < now ? "expired" : "expiry",
00615 tbuf);
00616 }
00617 result = dns_rbtnodechain_next(&chain, NULL, NULL);
00618 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
00619 if (result == ISC_R_NOMORE)
00620 result = ISC_R_SUCCESS;
00621 break;
00622 }
00623 }
00624
00625 cleanup:
00626 dns_rbtnodechain_invalidate(&chain);
00627 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00628 return (result);
00629 }
00630 #endif
00631
00632 isc_result_t
00633 dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
00634 isc_result_t result;
00635 isc_buffer_t *text = NULL;
00636 int len = 4096;
00637
00638 result = isc_buffer_allocate(ntatable->view->mctx, &text, len);
00639 if (result != ISC_R_SUCCESS)
00640 return (result);
00641
00642 result = dns_ntatable_totext(ntatable, &text);
00643
00644 if (isc_buffer_usedlength(text) != 0) {
00645 (void) putstr(&text, "\n");
00646 } else if (result == ISC_R_SUCCESS) {
00647 (void) putstr(&text, "none");
00648 } else {
00649 (void) putstr(&text, "could not dump NTA table: ");
00650 (void) putstr(&text, isc_result_totext(result));
00651 }
00652
00653 fprintf(fp, "%.*s", (int) isc_buffer_usedlength(text),
00654 (char *) isc_buffer_base(text));
00655 isc_buffer_free(&text);
00656 return (result);
00657 }
00658
00659 isc_result_t
00660 dns_ntatable_save(dns_ntatable_t *ntatable, FILE *fp) {
00661 isc_result_t result;
00662 dns_rbtnode_t *node;
00663 dns_rbtnodechain_t chain;
00664 isc_stdtime_t now;
00665 isc_boolean_t written = ISC_FALSE;
00666
00667 REQUIRE(VALID_NTATABLE(ntatable));
00668
00669 isc_stdtime_get(&now);
00670
00671 RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00672 dns_rbtnodechain_init(&chain, ntatable->view->mctx);
00673 result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
00674 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
00675 goto cleanup;
00676
00677 for (;;) {
00678 dns_rbtnodechain_current(&chain, NULL, NULL, &node);
00679 if (node->data != NULL) {
00680 dns_nta_t *n = (dns_nta_t *) node->data;
00681 if (now <= n->expiry) {
00682 isc_buffer_t b;
00683 char nbuf[DNS_NAME_FORMATSIZE + 1], tbuf[80];
00684 dns_fixedname_t fn;
00685 dns_name_t *name;
00686
00687 dns_fixedname_init(&fn);
00688 name = dns_fixedname_name(&fn);
00689 dns_rbt_fullnamefromnode(node, name);
00690
00691 isc_buffer_init(&b, nbuf, sizeof(nbuf));
00692 result = dns_name_totext(name, ISC_FALSE, &b);
00693 if (result != ISC_R_SUCCESS)
00694 goto skip;
00695
00696
00697 isc_buffer_putuint8(&b, 0);
00698
00699 isc_buffer_init(&b, tbuf, sizeof(tbuf));
00700 dns_time32_totext(n->expiry, &b);
00701
00702
00703 isc_buffer_putuint8(&b, 0);
00704
00705 fprintf(fp, "%s %s %s\n", nbuf,
00706 n->forced ? "forced" : "regular",
00707 tbuf);
00708 written = ISC_TRUE;
00709 }
00710 }
00711 skip:
00712 result = dns_rbtnodechain_next(&chain, NULL, NULL);
00713 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
00714 if (result == ISC_R_NOMORE)
00715 result = ISC_R_SUCCESS;
00716 break;
00717 }
00718 }
00719
00720 cleanup:
00721 dns_rbtnodechain_invalidate(&chain);
00722 RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
00723
00724 if (result != ISC_R_SUCCESS)
00725 return (result);
00726 else
00727 return (written ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
00728 }