Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: view.c,v 1.21 2026/04/08 00:16:14 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 <limits.h>
     20 #include <stdbool.h>
     21 
     22 #ifdef HAVE_LMDB
     23 #include <lmdb.h>
     24 #endif /* ifdef HAVE_LMDB */
     25 
     26 #include <isc/atomic.h>
     27 #include <isc/dir.h>
     28 #include <isc/file.h>
     29 #include <isc/hash.h>
     30 #include <isc/lex.h>
     31 #include <isc/md.h>
     32 #include <isc/result.h>
     33 #include <isc/stats.h>
     34 #include <isc/string.h>
     35 #include <isc/urcu.h>
     36 #include <isc/util.h>
     37 
     38 #include <dns/acl.h>
     39 #include <dns/adb.h>
     40 #include <dns/badcache.h>
     41 #include <dns/cache.h>
     42 #include <dns/db.h>
     43 #include <dns/dispatch.h>
     44 #include <dns/dlz.h>
     45 #include <dns/dns64.h>
     46 #include <dns/dnssec.h>
     47 #include <dns/forward.h>
     48 #include <dns/keytable.h>
     49 #include <dns/keyvalues.h>
     50 #include <dns/master.h>
     51 #include <dns/masterdump.h>
     52 #include <dns/nametree.h>
     53 #include <dns/nta.h>
     54 #include <dns/order.h>
     55 #include <dns/peer.h>
     56 #include <dns/rbt.h>
     57 #include <dns/rdataset.h>
     58 #include <dns/request.h>
     59 #include <dns/resolver.h>
     60 #include <dns/rpz.h>
     61 #include <dns/rrl.h>
     62 #include <dns/stats.h>
     63 #include <dns/time.h>
     64 #include <dns/transport.h>
     65 #include <dns/tsig.h>
     66 #include <dns/view.h>
     67 #include <dns/zone.h>
     68 #include <dns/zt.h>
     69 
     70 #define DNS_VIEW_DELONLYHASH 111
     71 
     72 /*%
     73  * Default maximum number of chained queries before we give up
     74  * to prevent CNAME loops.
     75  */
     76 #define DEFAULT_MAX_RESTARTS 11
     77 
     78 /*%
     79  * Default EDNS0 buffer size
     80  */
     81 #define DEFAULT_EDNS_BUFSIZE 1232
     82 
     83 isc_result_t
     84 dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
     85 		dns_dispatchmgr_t *dispatchmgr, dns_rdataclass_t rdclass,
     86 		const char *name, dns_view_t **viewp) {
     87 	dns_view_t *view = NULL;
     88 	isc_result_t result;
     89 	char buffer[1024];
     90 
     91 	REQUIRE(name != NULL);
     92 	REQUIRE(viewp != NULL && *viewp == NULL);
     93 
     94 	result = isc_file_sanitize(NULL, name, "nta", buffer, sizeof(buffer));
     95 	if (result != ISC_R_SUCCESS) {
     96 		return result;
     97 	}
     98 
     99 	view = isc_mem_get(mctx, sizeof(*view));
    100 	*view = (dns_view_t){
    101 		.rdclass = rdclass,
    102 		.name = isc_mem_strdup(mctx, name),
    103 		.nta_file = isc_mem_strdup(mctx, buffer),
    104 		.recursion = true,
    105 		.enablevalidation = true,
    106 		.minimalresponses = dns_minimal_no,
    107 		.transfer_format = dns_one_answer,
    108 		.msgcompression = true,
    109 		.provideixfr = true,
    110 		.maxcachettl = 7 * 24 * 3600,
    111 		.maxncachettl = 3 * 3600,
    112 		.dstport = 53,
    113 		.staleanswerttl = 1,
    114 		.staleanswersok = dns_stale_answer_conf,
    115 		.sendcookie = true,
    116 		.synthfromdnssec = true,
    117 		.trust_anchor_telemetry = true,
    118 		.root_key_sentinel = true,
    119 		.udpsize = DEFAULT_EDNS_BUFSIZE,
    120 		.max_restarts = DEFAULT_MAX_RESTARTS,
    121 	};
    122 
    123 	isc_refcount_init(&view->references, 1);
    124 	isc_refcount_init(&view->weakrefs, 1);
    125 
    126 	dns_fixedname_init(&view->redirectfixed);
    127 
    128 	ISC_LIST_INIT(view->dlz_searched);
    129 	ISC_LIST_INIT(view->dlz_unsearched);
    130 	ISC_LIST_INIT(view->dns64);
    131 
    132 	ISC_LINK_INIT(view, link);
    133 
    134 	isc_mem_attach(mctx, &view->mctx);
    135 
    136 	if (dispatchmgr != NULL) {
    137 		dns_dispatchmgr_attach(dispatchmgr, &view->dispatchmgr);
    138 	}
    139 
    140 	isc_mutex_init(&view->lock);
    141 
    142 	dns_zt_create(mctx, view, &view->zonetable);
    143 
    144 	dns_fwdtable_create(mctx, view, &view->fwdtable);
    145 
    146 	dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
    147 
    148 	view->failcache = dns_badcache_new(view->mctx, loopmgr);
    149 
    150 	isc_mutex_init(&view->new_zone_lock);
    151 
    152 	result = dns_order_create(view->mctx, &view->order);
    153 	if (result != ISC_R_SUCCESS) {
    154 		goto cleanup_new_zone_lock;
    155 	}
    156 
    157 	result = dns_peerlist_new(view->mctx, &view->peers);
    158 	if (result != ISC_R_SUCCESS) {
    159 		goto cleanup_order;
    160 	}
    161 
    162 	dns_aclenv_create(view->mctx, &view->aclenv);
    163 
    164 	dns_nametree_create(view->mctx, DNS_NAMETREE_COUNT, "sfd", &view->sfd);
    165 
    166 	view->magic = DNS_VIEW_MAGIC;
    167 	*viewp = view;
    168 
    169 	return ISC_R_SUCCESS;
    170 
    171 cleanup_order:
    172 	if (view->order != NULL) {
    173 		dns_order_detach(&view->order);
    174 	}
    175 
    176 cleanup_new_zone_lock:
    177 	isc_mutex_destroy(&view->new_zone_lock);
    178 	dns_badcache_destroy(&view->failcache);
    179 
    180 	if (view->dynamickeys != NULL) {
    181 		dns_tsigkeyring_detach(&view->dynamickeys);
    182 	}
    183 
    184 	isc_refcount_decrementz(&view->weakrefs);
    185 	isc_refcount_destroy(&view->weakrefs);
    186 
    187 	isc_refcount_decrementz(&view->references);
    188 	isc_refcount_destroy(&view->references);
    189 
    190 	dns_fwdtable_destroy(&view->fwdtable);
    191 	dns_zt_detach(&view->zonetable);
    192 
    193 	isc_mutex_destroy(&view->lock);
    194 
    195 	if (view->nta_file != NULL) {
    196 		isc_mem_free(mctx, view->nta_file);
    197 	}
    198 
    199 	isc_mem_free(mctx, view->name);
    200 	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
    201 
    202 	return result;
    203 }
    204 
    205 static void
    206 destroy(dns_view_t *view) {
    207 	dns_dns64_t *dns64;
    208 	dns_dlzdb_t *dlzdb;
    209 
    210 	REQUIRE(!ISC_LINK_LINKED(view, link));
    211 
    212 	isc_refcount_destroy(&view->references);
    213 	isc_refcount_destroy(&view->weakrefs);
    214 
    215 	if (view->order != NULL) {
    216 		dns_order_detach(&view->order);
    217 	}
    218 	if (view->peers != NULL) {
    219 		dns_peerlist_detach(&view->peers);
    220 	}
    221 
    222 	if (view->dynamickeys != NULL) {
    223 		isc_result_t result;
    224 		char template[PATH_MAX];
    225 		char keyfile[PATH_MAX];
    226 		FILE *fp = NULL;
    227 
    228 		result = isc_file_mktemplate(NULL, template, sizeof(template));
    229 		if (result == ISC_R_SUCCESS) {
    230 			(void)isc_file_openuniqueprivate(template, &fp);
    231 		}
    232 		if (fp != NULL) {
    233 			result = dns_tsigkeyring_dump(view->dynamickeys, fp);
    234 			if (result == ISC_R_SUCCESS) {
    235 				if (fclose(fp) == 0) {
    236 					result = isc_file_sanitize(
    237 						NULL, view->name, "tsigkeys",
    238 						keyfile, sizeof(keyfile));
    239 					if (result == ISC_R_SUCCESS) {
    240 						result = isc_file_rename(
    241 							template, keyfile);
    242 					}
    243 				}
    244 				if (result != ISC_R_SUCCESS) {
    245 					(void)remove(template);
    246 				}
    247 			} else {
    248 				(void)fclose(fp);
    249 				(void)remove(template);
    250 			}
    251 		}
    252 		dns_tsigkeyring_detach(&view->dynamickeys);
    253 	}
    254 	if (view->transports != NULL) {
    255 		dns_transport_list_detach(&view->transports);
    256 	}
    257 	if (view->statickeys != NULL) {
    258 		dns_tsigkeyring_detach(&view->statickeys);
    259 	}
    260 
    261 	/* These must have been detached in dns_view_detach() */
    262 	INSIST(view->adb == NULL);
    263 	INSIST(view->resolver == NULL);
    264 	INSIST(view->requestmgr == NULL);
    265 
    266 	dns_rrl_view_destroy(view);
    267 	if (view->rpzs != NULL) {
    268 		dns_rpz_zones_shutdown(view->rpzs);
    269 		dns_rpz_zones_detach(&view->rpzs);
    270 	}
    271 	if (view->catzs != NULL) {
    272 		dns_catz_zones_shutdown(view->catzs);
    273 		dns_catz_zones_detach(&view->catzs);
    274 	}
    275 	for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); dlzdb != NULL;
    276 	     dlzdb = ISC_LIST_HEAD(view->dlz_searched))
    277 	{
    278 		ISC_LIST_UNLINK(view->dlz_searched, dlzdb, link);
    279 		dns_dlzdestroy(&dlzdb);
    280 	}
    281 	for (dlzdb = ISC_LIST_HEAD(view->dlz_unsearched); dlzdb != NULL;
    282 	     dlzdb = ISC_LIST_HEAD(view->dlz_unsearched))
    283 	{
    284 		ISC_LIST_UNLINK(view->dlz_unsearched, dlzdb, link);
    285 		dns_dlzdestroy(&dlzdb);
    286 	}
    287 	if (view->hints != NULL) {
    288 		dns_db_detach(&view->hints);
    289 	}
    290 	if (view->cachedb != NULL) {
    291 		dns_db_detach(&view->cachedb);
    292 	}
    293 	if (view->cache != NULL) {
    294 		dns_cache_detach(&view->cache);
    295 	}
    296 	if (view->nocasecompress != NULL) {
    297 		dns_acl_detach(&view->nocasecompress);
    298 	}
    299 	if (view->matchclients != NULL) {
    300 		dns_acl_detach(&view->matchclients);
    301 	}
    302 	if (view->matchdestinations != NULL) {
    303 		dns_acl_detach(&view->matchdestinations);
    304 	}
    305 	if (view->cacheacl != NULL) {
    306 		dns_acl_detach(&view->cacheacl);
    307 	}
    308 	if (view->cacheonacl != NULL) {
    309 		dns_acl_detach(&view->cacheonacl);
    310 	}
    311 	if (view->queryacl != NULL) {
    312 		dns_acl_detach(&view->queryacl);
    313 	}
    314 	if (view->queryonacl != NULL) {
    315 		dns_acl_detach(&view->queryonacl);
    316 	}
    317 	if (view->recursionacl != NULL) {
    318 		dns_acl_detach(&view->recursionacl);
    319 	}
    320 	if (view->recursiononacl != NULL) {
    321 		dns_acl_detach(&view->recursiononacl);
    322 	}
    323 	if (view->sortlist != NULL) {
    324 		dns_acl_detach(&view->sortlist);
    325 	}
    326 	if (view->transferacl != NULL) {
    327 		dns_acl_detach(&view->transferacl);
    328 	}
    329 	if (view->notifyacl != NULL) {
    330 		dns_acl_detach(&view->notifyacl);
    331 	}
    332 	if (view->updateacl != NULL) {
    333 		dns_acl_detach(&view->updateacl);
    334 	}
    335 	if (view->upfwdacl != NULL) {
    336 		dns_acl_detach(&view->upfwdacl);
    337 	}
    338 	if (view->denyansweracl != NULL) {
    339 		dns_acl_detach(&view->denyansweracl);
    340 	}
    341 	if (view->pad_acl != NULL) {
    342 		dns_acl_detach(&view->pad_acl);
    343 	}
    344 	if (view->proxyacl != NULL) {
    345 		dns_acl_detach(&view->proxyacl);
    346 	}
    347 	if (view->proxyonacl != NULL) {
    348 		dns_acl_detach(&view->proxyonacl);
    349 	}
    350 	if (view->answeracl_exclude != NULL) {
    351 		dns_nametree_detach(&view->answeracl_exclude);
    352 	}
    353 	if (view->denyanswernames != NULL) {
    354 		dns_nametree_detach(&view->denyanswernames);
    355 	}
    356 	if (view->answernames_exclude != NULL) {
    357 		dns_nametree_detach(&view->answernames_exclude);
    358 	}
    359 	if (view->sfd != NULL) {
    360 		dns_nametree_detach(&view->sfd);
    361 	}
    362 	if (view->secroots_priv != NULL) {
    363 		dns_keytable_detach(&view->secroots_priv);
    364 	}
    365 	if (view->ntatable_priv != NULL) {
    366 		dns_ntatable_detach(&view->ntatable_priv);
    367 	}
    368 	for (dns64 = ISC_LIST_HEAD(view->dns64); dns64 != NULL;
    369 	     dns64 = ISC_LIST_HEAD(view->dns64))
    370 	{
    371 		dns_dns64_unlink(&view->dns64, dns64);
    372 		dns_dns64_destroy(&dns64);
    373 	}
    374 	if (view->managed_keys != NULL) {
    375 		dns_zone_detach(&view->managed_keys);
    376 	}
    377 	if (view->redirect != NULL) {
    378 		dns_zone_detach(&view->redirect);
    379 	}
    380 #ifdef HAVE_DNSTAP
    381 	if (view->dtenv != NULL) {
    382 		dns_dtenv_detach(&view->dtenv);
    383 	}
    384 #endif /* HAVE_DNSTAP */
    385 	dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
    386 	if (view->new_zone_file != NULL) {
    387 		isc_mem_free(view->mctx, view->new_zone_file);
    388 		view->new_zone_file = NULL;
    389 	}
    390 	if (view->new_zone_dir != NULL) {
    391 		isc_mem_free(view->mctx, view->new_zone_dir);
    392 		view->new_zone_dir = NULL;
    393 	}
    394 #ifdef HAVE_LMDB
    395 	if (view->new_zone_dbenv != NULL) {
    396 		mdb_env_close((MDB_env *)view->new_zone_dbenv);
    397 		view->new_zone_dbenv = NULL;
    398 	}
    399 	if (view->new_zone_db != NULL) {
    400 		isc_mem_free(view->mctx, view->new_zone_db);
    401 		view->new_zone_db = NULL;
    402 	}
    403 #endif /* HAVE_LMDB */
    404 	dns_fwdtable_destroy(&view->fwdtable);
    405 	dns_aclenv_detach(&view->aclenv);
    406 	if (view->failcache != NULL) {
    407 		dns_badcache_destroy(&view->failcache);
    408 	}
    409 	isc_mutex_destroy(&view->new_zone_lock);
    410 	isc_mutex_destroy(&view->lock);
    411 	isc_refcount_destroy(&view->references);
    412 	isc_refcount_destroy(&view->weakrefs);
    413 	isc_mem_free(view->mctx, view->nta_file);
    414 	isc_mem_free(view->mctx, view->name);
    415 	if (view->hooktable != NULL && view->hooktable_free != NULL) {
    416 		view->hooktable_free(view->mctx, &view->hooktable);
    417 	}
    418 	if (view->plugins != NULL && view->plugins_free != NULL) {
    419 		view->plugins_free(view->mctx, &view->plugins);
    420 	}
    421 	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
    422 }
    423 
    424 void
    425 dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
    426 	REQUIRE(DNS_VIEW_VALID(source));
    427 	REQUIRE(targetp != NULL && *targetp == NULL);
    428 
    429 	isc_refcount_increment(&source->references);
    430 
    431 	*targetp = source;
    432 }
    433 
    434 void
    435 dns_view_detach(dns_view_t **viewp) {
    436 	dns_view_t *view = NULL;
    437 
    438 	REQUIRE(viewp != NULL && DNS_VIEW_VALID(*viewp));
    439 
    440 	view = *viewp;
    441 	*viewp = NULL;
    442 
    443 	if (isc_refcount_decrement(&view->references) == 1) {
    444 		dns_zone_t *mkzone = NULL, *rdzone = NULL;
    445 		dns_zt_t *zonetable = NULL;
    446 		dns_resolver_t *resolver = NULL;
    447 		dns_adb_t *adb = NULL;
    448 		dns_requestmgr_t *requestmgr = NULL;
    449 		dns_dispatchmgr_t *dispatchmgr = NULL;
    450 
    451 		isc_refcount_destroy(&view->references);
    452 
    453 		/* Shutdown the attached objects first */
    454 		if (view->resolver != NULL) {
    455 			dns_resolver_shutdown(view->resolver);
    456 		}
    457 
    458 		rcu_read_lock();
    459 		adb = rcu_dereference(view->adb);
    460 		if (adb != NULL) {
    461 			dns_adb_shutdown(adb);
    462 		}
    463 		rcu_read_unlock();
    464 
    465 		if (view->requestmgr != NULL) {
    466 			dns_requestmgr_shutdown(view->requestmgr);
    467 		}
    468 
    469 		/* Swap the pointers under the lock */
    470 		LOCK(&view->lock);
    471 
    472 		if (view->resolver != NULL) {
    473 			resolver = view->resolver;
    474 			view->resolver = NULL;
    475 		}
    476 
    477 		rcu_read_lock();
    478 		zonetable = rcu_xchg_pointer(&view->zonetable, NULL);
    479 		if (zonetable != NULL) {
    480 			if (view->flush) {
    481 				dns_zt_flush(zonetable);
    482 			}
    483 		}
    484 		adb = rcu_xchg_pointer(&view->adb, NULL);
    485 		dispatchmgr = rcu_xchg_pointer(&view->dispatchmgr, NULL);
    486 		rcu_read_unlock();
    487 
    488 		if (view->requestmgr != NULL) {
    489 			requestmgr = view->requestmgr;
    490 			view->requestmgr = NULL;
    491 		}
    492 		if (view->managed_keys != NULL) {
    493 			mkzone = view->managed_keys;
    494 			view->managed_keys = NULL;
    495 			if (view->flush) {
    496 				dns_zone_flush(mkzone);
    497 			}
    498 		}
    499 		if (view->redirect != NULL) {
    500 			rdzone = view->redirect;
    501 			view->redirect = NULL;
    502 			if (view->flush) {
    503 				dns_zone_flush(rdzone);
    504 			}
    505 		}
    506 		if (view->catzs != NULL) {
    507 			dns_catz_zones_shutdown(view->catzs);
    508 			dns_catz_zones_detach(&view->catzs);
    509 		}
    510 		if (view->ntatable_priv != NULL) {
    511 			dns_ntatable_shutdown(view->ntatable_priv);
    512 		}
    513 		UNLOCK(&view->lock);
    514 
    515 		/* Detach outside view lock */
    516 		if (resolver != NULL) {
    517 			dns_resolver_detach(&resolver);
    518 		}
    519 		synchronize_rcu();
    520 		if (dispatchmgr != NULL) {
    521 			dns_dispatchmgr_detach(&dispatchmgr);
    522 		}
    523 		if (adb != NULL) {
    524 			dns_adb_detach(&adb);
    525 		}
    526 		if (zonetable != NULL) {
    527 			dns_zt_detach(&zonetable);
    528 		}
    529 		if (requestmgr != NULL) {
    530 			dns_requestmgr_detach(&requestmgr);
    531 		}
    532 		if (mkzone != NULL) {
    533 			dns_zone_detach(&mkzone);
    534 		}
    535 		if (rdzone != NULL) {
    536 			dns_zone_detach(&rdzone);
    537 		}
    538 
    539 		dns_view_weakdetach(&view);
    540 	}
    541 }
    542 
    543 static isc_result_t
    544 dialup(dns_zone_t *zone, void *dummy) {
    545 	UNUSED(dummy);
    546 	dns_zone_dialup(zone);
    547 	return ISC_R_SUCCESS;
    548 }
    549 
    550 void
    551 dns_view_dialup(dns_view_t *view) {
    552 	dns_zt_t *zonetable = NULL;
    553 
    554 	REQUIRE(DNS_VIEW_VALID(view));
    555 
    556 	rcu_read_lock();
    557 	zonetable = rcu_dereference(view->zonetable);
    558 	if (zonetable != NULL) {
    559 		(void)dns_zt_apply(zonetable, false, NULL, dialup, NULL);
    560 	}
    561 	rcu_read_unlock();
    562 }
    563 
    564 void
    565 dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
    566 	REQUIRE(DNS_VIEW_VALID(source));
    567 	REQUIRE(targetp != NULL && *targetp == NULL);
    568 
    569 	isc_refcount_increment(&source->weakrefs);
    570 
    571 	*targetp = source;
    572 }
    573 
    574 void
    575 dns_view_weakdetach(dns_view_t **viewp) {
    576 	dns_view_t *view = NULL;
    577 
    578 	REQUIRE(viewp != NULL);
    579 
    580 	view = *viewp;
    581 	*viewp = NULL;
    582 
    583 	REQUIRE(DNS_VIEW_VALID(view));
    584 
    585 	if (isc_refcount_decrement(&view->weakrefs) == 1) {
    586 		destroy(view);
    587 	}
    588 }
    589 
    590 isc_result_t
    591 dns_view_createresolver(dns_view_t *view, isc_nm_t *netmgr,
    592 			unsigned int options, isc_tlsctx_cache_t *tlsctx_cache,
    593 			dns_dispatch_t *dispatchv4,
    594 			dns_dispatch_t *dispatchv6) {
    595 	isc_result_t result;
    596 	isc_mem_t *mctx = NULL;
    597 	isc_loopmgr_t *loopmgr = isc_loop_getloopmgr(isc_loop());
    598 
    599 	REQUIRE(DNS_VIEW_VALID(view));
    600 	REQUIRE(!view->frozen);
    601 	REQUIRE(view->resolver == NULL);
    602 	REQUIRE(view->dispatchmgr != NULL);
    603 
    604 	result = dns_resolver_create(view, loopmgr, netmgr, options,
    605 				     tlsctx_cache, dispatchv4, dispatchv6,
    606 				     &view->resolver);
    607 	if (result != ISC_R_SUCCESS) {
    608 		return result;
    609 	}
    610 
    611 	isc_mem_create(&mctx);
    612 	isc_mem_setname(mctx, "ADB");
    613 	dns_adb_create(mctx, view, &view->adb);
    614 	isc_mem_detach(&mctx);
    615 
    616 	result = dns_requestmgr_create(view->mctx, loopmgr, view->dispatchmgr,
    617 				       dispatchv4, dispatchv6,
    618 				       &view->requestmgr);
    619 	if (result != ISC_R_SUCCESS) {
    620 		goto cleanup_adb;
    621 	}
    622 
    623 	return ISC_R_SUCCESS;
    624 
    625 cleanup_adb:
    626 	dns_adb_shutdown(view->adb);
    627 	dns_adb_detach(&view->adb);
    628 
    629 	dns_resolver_shutdown(view->resolver);
    630 	dns_resolver_detach(&view->resolver);
    631 
    632 	return result;
    633 }
    634 
    635 void
    636 dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared) {
    637 	REQUIRE(DNS_VIEW_VALID(view));
    638 	REQUIRE(!view->frozen);
    639 
    640 	view->cacheshared = shared;
    641 	if (view->cache != NULL) {
    642 		dns_db_detach(&view->cachedb);
    643 		dns_cache_detach(&view->cache);
    644 	}
    645 	dns_cache_attach(cache, &view->cache);
    646 	dns_cache_attachdb(cache, &view->cachedb);
    647 	INSIST(DNS_DB_VALID(view->cachedb));
    648 
    649 	dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
    650 	dns_cache_setmaxtypepername(view->cache, view->maxtypepername);
    651 }
    652 
    653 bool
    654 dns_view_iscacheshared(dns_view_t *view) {
    655 	REQUIRE(DNS_VIEW_VALID(view));
    656 
    657 	return view->cacheshared;
    658 }
    659 
    660 void
    661 dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
    662 	REQUIRE(DNS_VIEW_VALID(view));
    663 	REQUIRE(!view->frozen);
    664 	REQUIRE(view->hints == NULL);
    665 	REQUIRE(dns_db_iszone(hints));
    666 
    667 	dns_db_attach(hints, &view->hints);
    668 }
    669 
    670 void
    671 dns_view_settransports(dns_view_t *view, dns_transport_list_t *list) {
    672 	REQUIRE(DNS_VIEW_VALID(view));
    673 	REQUIRE(list != NULL);
    674 	if (view->transports != NULL) {
    675 		dns_transport_list_detach(&view->transports);
    676 	}
    677 	dns_transport_list_attach(list, &view->transports);
    678 }
    679 
    680 void
    681 dns_view_setkeyring(dns_view_t *view, dns_tsigkeyring_t *ring) {
    682 	REQUIRE(DNS_VIEW_VALID(view));
    683 	REQUIRE(ring != NULL);
    684 	if (view->statickeys != NULL) {
    685 		dns_tsigkeyring_detach(&view->statickeys);
    686 	}
    687 	dns_tsigkeyring_attach(ring, &view->statickeys);
    688 }
    689 
    690 void
    691 dns_view_setdynamickeyring(dns_view_t *view, dns_tsigkeyring_t *ring) {
    692 	REQUIRE(DNS_VIEW_VALID(view));
    693 	REQUIRE(ring != NULL);
    694 	if (view->dynamickeys != NULL) {
    695 		dns_tsigkeyring_detach(&view->dynamickeys);
    696 	}
    697 	dns_tsigkeyring_attach(ring, &view->dynamickeys);
    698 }
    699 
    700 void
    701 dns_view_getdynamickeyring(dns_view_t *view, dns_tsigkeyring_t **ringp) {
    702 	REQUIRE(DNS_VIEW_VALID(view));
    703 	REQUIRE(ringp != NULL && *ringp == NULL);
    704 	if (view->dynamickeys != NULL) {
    705 		dns_tsigkeyring_attach(view->dynamickeys, ringp);
    706 	}
    707 }
    708 
    709 void
    710 dns_view_restorekeyring(dns_view_t *view) {
    711 	FILE *fp;
    712 	char keyfile[PATH_MAX];
    713 	isc_result_t result;
    714 
    715 	REQUIRE(DNS_VIEW_VALID(view));
    716 
    717 	if (view->dynamickeys != NULL) {
    718 		result = isc_file_sanitize(NULL, view->name, "tsigkeys",
    719 					   keyfile, sizeof(keyfile));
    720 		if (result == ISC_R_SUCCESS) {
    721 			fp = fopen(keyfile, "r");
    722 			if (fp != NULL) {
    723 				dns_tsigkeyring_restore(view->dynamickeys, fp);
    724 				(void)fclose(fp);
    725 			}
    726 		}
    727 	}
    728 }
    729 
    730 void
    731 dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
    732 	REQUIRE(DNS_VIEW_VALID(view));
    733 	view->dstport = dstport;
    734 }
    735 
    736 void
    737 dns_view_freeze(dns_view_t *view) {
    738 	REQUIRE(DNS_VIEW_VALID(view));
    739 	REQUIRE(!view->frozen);
    740 
    741 	if (view->resolver != NULL) {
    742 		INSIST(view->cachedb != NULL);
    743 		dns_resolver_freeze(view->resolver);
    744 	}
    745 	view->frozen = true;
    746 }
    747 
    748 void
    749 dns_view_thaw(dns_view_t *view) {
    750 	REQUIRE(DNS_VIEW_VALID(view));
    751 	REQUIRE(view->frozen);
    752 
    753 	view->frozen = false;
    754 }
    755 
    756 isc_result_t
    757 dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
    758 	isc_result_t result;
    759 	dns_zt_t *zonetable = NULL;
    760 
    761 	REQUIRE(DNS_VIEW_VALID(view));
    762 	REQUIRE(!view->frozen);
    763 
    764 	rcu_read_lock();
    765 	zonetable = rcu_dereference(view->zonetable);
    766 	if (zonetable != NULL) {
    767 		result = dns_zt_mount(zonetable, zone);
    768 	} else {
    769 		result = ISC_R_SHUTTINGDOWN;
    770 	}
    771 	rcu_read_unlock();
    772 
    773 	return result;
    774 }
    775 
    776 isc_result_t
    777 dns_view_delzone(dns_view_t *view, dns_zone_t *zone) {
    778 	isc_result_t result;
    779 	dns_zt_t *zonetable = NULL;
    780 
    781 	REQUIRE(DNS_VIEW_VALID(view));
    782 
    783 	dns_zone_prepare_shutdown(zone);
    784 
    785 	rcu_read_lock();
    786 	zonetable = rcu_dereference(view->zonetable);
    787 	if (zonetable != NULL) {
    788 		result = dns_zt_unmount(zonetable, zone);
    789 	} else {
    790 		result = ISC_R_SUCCESS;
    791 	}
    792 	rcu_read_unlock();
    793 
    794 	return result;
    795 }
    796 
    797 isc_result_t
    798 dns_view_findzone(dns_view_t *view, const dns_name_t *name,
    799 		  unsigned int options, dns_zone_t **zonep) {
    800 	isc_result_t result;
    801 	dns_zt_t *zonetable = NULL;
    802 
    803 	REQUIRE(DNS_VIEW_VALID(view));
    804 
    805 	rcu_read_lock();
    806 	zonetable = rcu_dereference(view->zonetable);
    807 	if (zonetable != NULL) {
    808 		result = dns_zt_find(zonetable, name, options, zonep);
    809 	} else {
    810 		result = ISC_R_NOTFOUND;
    811 	}
    812 	rcu_read_unlock();
    813 
    814 	return result;
    815 }
    816 
    817 isc_result_t
    818 dns_view_find(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
    819 	      isc_stdtime_t now, unsigned int options, bool use_hints,
    820 	      bool use_static_stub, dns_db_t **dbp, dns_dbnode_t **nodep,
    821 	      dns_name_t *foundname, dns_rdataset_t *rdataset,
    822 	      dns_rdataset_t *sigrdataset) {
    823 	isc_result_t result;
    824 	dns_db_t *db = NULL, *zdb = NULL;
    825 	dns_dbnode_t *node = NULL, *znode = NULL;
    826 	bool is_cache, is_staticstub_zone;
    827 	dns_rdataset_t zrdataset, zsigrdataset;
    828 	dns_zone_t *zone = NULL;
    829 	dns_zt_t *zonetable = NULL;
    830 
    831 	/*
    832 	 * Find an rdataset whose owner name is 'name', and whose type is
    833 	 * 'type'.
    834 	 */
    835 
    836 	REQUIRE(DNS_VIEW_VALID(view));
    837 	REQUIRE(view->frozen);
    838 	REQUIRE(type != dns_rdatatype_rrsig);
    839 	REQUIRE(rdataset != NULL); /* XXXBEW - remove this */
    840 	REQUIRE(nodep == NULL || *nodep == NULL);
    841 
    842 	/*
    843 	 * Initialize.
    844 	 */
    845 	dns_rdataset_init(&zrdataset);
    846 	dns_rdataset_init(&zsigrdataset);
    847 
    848 	/*
    849 	 * Find a database to answer the query.
    850 	 */
    851 	is_staticstub_zone = false;
    852 	rcu_read_lock();
    853 	zonetable = rcu_dereference(view->zonetable);
    854 	if (zonetable != NULL) {
    855 		result = dns_zt_find(zonetable, name, DNS_ZTFIND_MIRROR, &zone);
    856 	} else {
    857 		result = ISC_R_SHUTTINGDOWN;
    858 	}
    859 	rcu_read_unlock();
    860 	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
    861 	    !use_static_stub)
    862 	{
    863 		result = ISC_R_NOTFOUND;
    864 	}
    865 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    866 		result = dns_zone_getdb(zone, &db);
    867 		if (result != ISC_R_SUCCESS && view->cachedb != NULL) {
    868 			dns_db_attach(view->cachedb, &db);
    869 		} else if (result != ISC_R_SUCCESS) {
    870 			goto cleanup;
    871 		}
    872 		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
    873 		    dns_name_equal(name, dns_zone_getorigin(zone)))
    874 		{
    875 			is_staticstub_zone = true;
    876 		}
    877 	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL) {
    878 		dns_db_attach(view->cachedb, &db);
    879 	} else {
    880 		goto cleanup;
    881 	}
    882 
    883 	is_cache = dns_db_iscache(db);
    884 
    885 db_find:
    886 	/*
    887 	 * Now look for an answer in the database.
    888 	 */
    889 	result = dns_db_find(db, name, NULL, type, options, now, &node,
    890 			     foundname, rdataset, sigrdataset);
    891 
    892 	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
    893 		if (dns_rdataset_isassociated(rdataset)) {
    894 			dns_rdataset_disassociate(rdataset);
    895 		}
    896 		if (sigrdataset != NULL &&
    897 		    dns_rdataset_isassociated(sigrdataset))
    898 		{
    899 			dns_rdataset_disassociate(sigrdataset);
    900 		}
    901 		if (node != NULL) {
    902 			dns_db_detachnode(db, &node);
    903 		}
    904 		if (!is_cache) {
    905 			dns_db_detach(&db);
    906 			if (view->cachedb != NULL && !is_staticstub_zone) {
    907 				/*
    908 				 * Either the answer is in the cache, or we
    909 				 * don't know it.
    910 				 * Note that if the result comes from a
    911 				 * static-stub zone we stop the search here
    912 				 * (see the function description in view.h).
    913 				 */
    914 				is_cache = true;
    915 				dns_db_attach(view->cachedb, &db);
    916 				goto db_find;
    917 			}
    918 		} else {
    919 			/*
    920 			 * We don't have the data in the cache.  If we've got
    921 			 * glue from the zone, use it.
    922 			 */
    923 			if (dns_rdataset_isassociated(&zrdataset)) {
    924 				dns_rdataset_clone(&zrdataset, rdataset);
    925 				if (sigrdataset != NULL &&
    926 				    dns_rdataset_isassociated(&zsigrdataset))
    927 				{
    928 					dns_rdataset_clone(&zsigrdataset,
    929 							   sigrdataset);
    930 				}
    931 				result = DNS_R_GLUE;
    932 				if (db != NULL) {
    933 					dns_db_detach(&db);
    934 				}
    935 				dns_db_attach(zdb, &db);
    936 				dns_db_attachnode(db, znode, &node);
    937 				goto cleanup;
    938 			}
    939 		}
    940 		/*
    941 		 * We don't know the answer.
    942 		 */
    943 		result = ISC_R_NOTFOUND;
    944 	} else if (result == DNS_R_GLUE) {
    945 		/*
    946 		 * Glue is the answer wanted.
    947 		 */
    948 		result = ISC_R_SUCCESS;
    949 	}
    950 
    951 	if (result == ISC_R_NOTFOUND && !is_staticstub_zone && use_hints &&
    952 	    view->hints != NULL)
    953 	{
    954 		if (dns_rdataset_isassociated(rdataset)) {
    955 			dns_rdataset_disassociate(rdataset);
    956 		}
    957 		if (sigrdataset != NULL &&
    958 		    dns_rdataset_isassociated(sigrdataset))
    959 		{
    960 			dns_rdataset_disassociate(sigrdataset);
    961 		}
    962 		if (db != NULL) {
    963 			if (node != NULL) {
    964 				dns_db_detachnode(db, &node);
    965 			}
    966 			dns_db_detach(&db);
    967 		}
    968 		result = dns_db_find(view->hints, name, NULL, type, options,
    969 				     now, &node, foundname, rdataset,
    970 				     sigrdataset);
    971 		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
    972 			/*
    973 			 * We just used a hint.  Let the resolver know it
    974 			 * should consider priming.
    975 			 */
    976 			dns_resolver_t *res = NULL;
    977 			result = dns_view_getresolver(view, &res);
    978 			if (result == ISC_R_SUCCESS) {
    979 				dns_resolver_prime(res);
    980 				dns_db_attach(view->hints, &db);
    981 				dns_resolver_detach(&res);
    982 				result = DNS_R_HINT;
    983 			}
    984 		} else if (result == DNS_R_NXRRSET) {
    985 			dns_db_attach(view->hints, &db);
    986 			result = DNS_R_HINTNXRRSET;
    987 		} else if (result == DNS_R_NXDOMAIN) {
    988 			result = ISC_R_NOTFOUND;
    989 		}
    990 
    991 		/*
    992 		 * Cleanup if non-standard hints are used.
    993 		 */
    994 		if (db == NULL && node != NULL) {
    995 			dns_db_detachnode(view->hints, &node);
    996 		}
    997 	}
    998 
    999 cleanup:
   1000 	if (dns_rdataset_isassociated(&zrdataset)) {
   1001 		dns_rdataset_disassociate(&zrdataset);
   1002 		if (dns_rdataset_isassociated(&zsigrdataset)) {
   1003 			dns_rdataset_disassociate(&zsigrdataset);
   1004 		}
   1005 	}
   1006 
   1007 	if (zdb != NULL) {
   1008 		if (znode != NULL) {
   1009 			dns_db_detachnode(zdb, &znode);
   1010 		}
   1011 		dns_db_detach(&zdb);
   1012 	}
   1013 
   1014 	if (db != NULL) {
   1015 		if (node != NULL) {
   1016 			if (nodep != NULL) {
   1017 				*nodep = node;
   1018 			} else {
   1019 				dns_db_detachnode(db, &node);
   1020 			}
   1021 		}
   1022 		if (dbp != NULL) {
   1023 			*dbp = db;
   1024 		} else {
   1025 			dns_db_detach(&db);
   1026 		}
   1027 	} else {
   1028 		INSIST(node == NULL);
   1029 	}
   1030 
   1031 	if (zone != NULL) {
   1032 		dns_zone_detach(&zone);
   1033 	}
   1034 
   1035 	return result;
   1036 }
   1037 
   1038 isc_result_t
   1039 dns_view_simplefind(dns_view_t *view, const dns_name_t *name,
   1040 		    dns_rdatatype_t type, isc_stdtime_t now,
   1041 		    unsigned int options, bool use_hints,
   1042 		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   1043 	isc_result_t result;
   1044 	dns_fixedname_t foundname;
   1045 
   1046 	dns_fixedname_init(&foundname);
   1047 	result = dns_view_find(view, name, type, now, options, use_hints, false,
   1048 			       NULL, NULL, dns_fixedname_name(&foundname),
   1049 			       rdataset, sigrdataset);
   1050 	if (result == DNS_R_NXDOMAIN) {
   1051 		/*
   1052 		 * The rdataset and sigrdataset of the relevant NSEC record
   1053 		 * may be returned, but the caller cannot use them because
   1054 		 * foundname is not returned by this simplified API.  We
   1055 		 * disassociate them here to prevent any misuse by the caller.
   1056 		 */
   1057 		if (dns_rdataset_isassociated(rdataset)) {
   1058 			dns_rdataset_disassociate(rdataset);
   1059 		}
   1060 		if (sigrdataset != NULL &&
   1061 		    dns_rdataset_isassociated(sigrdataset))
   1062 		{
   1063 			dns_rdataset_disassociate(sigrdataset);
   1064 		}
   1065 	} else if (result != ISC_R_SUCCESS && result != DNS_R_GLUE &&
   1066 		   result != DNS_R_HINT && result != DNS_R_NCACHENXDOMAIN &&
   1067 		   result != DNS_R_NCACHENXRRSET && result != DNS_R_NXRRSET &&
   1068 		   result != DNS_R_HINTNXRRSET && result != ISC_R_NOTFOUND)
   1069 	{
   1070 		if (dns_rdataset_isassociated(rdataset)) {
   1071 			dns_rdataset_disassociate(rdataset);
   1072 		}
   1073 		if (sigrdataset != NULL &&
   1074 		    dns_rdataset_isassociated(sigrdataset))
   1075 		{
   1076 			dns_rdataset_disassociate(sigrdataset);
   1077 		}
   1078 		result = ISC_R_NOTFOUND;
   1079 	}
   1080 
   1081 	return result;
   1082 }
   1083 
   1084 isc_result_t
   1085 dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
   1086 		     dns_name_t *fname, dns_name_t *dcname, isc_stdtime_t now,
   1087 		     unsigned int options, bool use_hints, bool use_cache,
   1088 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   1089 	isc_result_t result;
   1090 	dns_db_t *db = NULL;
   1091 	bool is_cache, use_zone = false, try_hints = false;
   1092 	dns_zone_t *zone = NULL;
   1093 	dns_name_t *zfname = NULL;
   1094 	dns_zt_t *zonetable = NULL;
   1095 	dns_rdataset_t zrdataset, zsigrdataset;
   1096 	dns_fixedname_t zfixedname;
   1097 	unsigned int ztoptions = DNS_ZTFIND_MIRROR;
   1098 
   1099 	REQUIRE(DNS_VIEW_VALID(view));
   1100 	REQUIRE(view->frozen);
   1101 
   1102 	/*
   1103 	 * Initialize.
   1104 	 */
   1105 	dns_fixedname_init(&zfixedname);
   1106 	dns_rdataset_init(&zrdataset);
   1107 	dns_rdataset_init(&zsigrdataset);
   1108 
   1109 	/*
   1110 	 * Find the right database.
   1111 	 */
   1112 	if ((options & DNS_DBFIND_NOEXACT) != 0) {
   1113 		ztoptions |= DNS_ZTFIND_NOEXACT;
   1114 	}
   1115 	rcu_read_lock();
   1116 	zonetable = rcu_dereference(view->zonetable);
   1117 	if (zonetable != NULL) {
   1118 		result = dns_zt_find(zonetable, name, ztoptions, &zone);
   1119 	} else {
   1120 		result = ISC_R_SHUTTINGDOWN;
   1121 	}
   1122 	rcu_read_unlock();
   1123 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
   1124 		result = dns_zone_getdb(zone, &db);
   1125 	}
   1126 	if (result == ISC_R_NOTFOUND) {
   1127 		/*
   1128 		 * We're not directly authoritative for this query name, nor
   1129 		 * is it a subdomain of any zone for which we're
   1130 		 * authoritative.
   1131 		 */
   1132 		if (use_cache && view->cachedb != NULL) {
   1133 			/*
   1134 			 * We have a cache; try it.
   1135 			 */
   1136 			dns_db_attach(view->cachedb, &db);
   1137 		} else if (use_hints && view->hints != NULL) {
   1138 			/*
   1139 			 * Maybe we have hints...
   1140 			 */
   1141 			try_hints = true;
   1142 			goto finish;
   1143 		} else {
   1144 			result = DNS_R_NXDOMAIN;
   1145 			goto cleanup;
   1146 		}
   1147 	} else if (result != ISC_R_SUCCESS) {
   1148 		/*
   1149 		 * Something is broken.
   1150 		 */
   1151 		goto cleanup;
   1152 	}
   1153 	is_cache = dns_db_iscache(db);
   1154 
   1155 db_find:
   1156 	/*
   1157 	 * Look for the zonecut.
   1158 	 */
   1159 	if (!is_cache) {
   1160 		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
   1161 				     now, NULL, fname, rdataset, sigrdataset);
   1162 		if (result == DNS_R_DELEGATION) {
   1163 			result = ISC_R_SUCCESS;
   1164 		} else if (result != ISC_R_SUCCESS) {
   1165 			goto cleanup;
   1166 		}
   1167 
   1168 		/*
   1169 		 * Tag static stub NS RRset so that when we look for
   1170 		 * addresses we use the configured server addresses.
   1171 		 */
   1172 		if (dns_zone_gettype(zone) == dns_zone_staticstub) {
   1173 			rdataset->attributes |= DNS_RDATASETATTR_STATICSTUB;
   1174 		}
   1175 
   1176 		if (use_cache && view->cachedb != NULL && db != view->hints) {
   1177 			/*
   1178 			 * We found an answer, but the cache may be better.
   1179 			 */
   1180 			zfname = dns_fixedname_name(&zfixedname);
   1181 			dns_name_copy(fname, zfname);
   1182 			dns_rdataset_clone(rdataset, &zrdataset);
   1183 			dns_rdataset_disassociate(rdataset);
   1184 			if (sigrdataset != NULL &&
   1185 			    dns_rdataset_isassociated(sigrdataset))
   1186 			{
   1187 				dns_rdataset_clone(sigrdataset, &zsigrdataset);
   1188 				dns_rdataset_disassociate(sigrdataset);
   1189 			}
   1190 			dns_db_detach(&db);
   1191 			dns_db_attach(view->cachedb, &db);
   1192 			is_cache = true;
   1193 			goto db_find;
   1194 		}
   1195 	} else {
   1196 		result = dns_db_findzonecut(db, name, options, now, NULL, fname,
   1197 					    dcname, rdataset, sigrdataset);
   1198 		if (result == ISC_R_SUCCESS) {
   1199 			if (zfname != NULL &&
   1200 			    (!dns_name_issubdomain(fname, zfname) ||
   1201 			     (dns_zone_gettype(zone) == dns_zone_staticstub &&
   1202 			      dns_name_equal(fname, zfname))))
   1203 			{
   1204 				/*
   1205 				 * We found a zonecut in the cache, but our
   1206 				 * zone delegation is better.
   1207 				 */
   1208 				use_zone = true;
   1209 			}
   1210 		} else if (result == ISC_R_NOTFOUND) {
   1211 			if (zfname != NULL) {
   1212 				/*
   1213 				 * We didn't find anything in the cache, but we
   1214 				 * have a zone delegation, so use it.
   1215 				 */
   1216 				use_zone = true;
   1217 				result = ISC_R_SUCCESS;
   1218 			} else if (use_hints && view->hints != NULL) {
   1219 				/*
   1220 				 * Maybe we have hints...
   1221 				 */
   1222 				try_hints = true;
   1223 				result = ISC_R_SUCCESS;
   1224 			} else {
   1225 				result = DNS_R_NXDOMAIN;
   1226 			}
   1227 		} else {
   1228 			/*
   1229 			 * Something bad happened.
   1230 			 */
   1231 			goto cleanup;
   1232 		}
   1233 	}
   1234 
   1235 finish:
   1236 	if (use_zone) {
   1237 		if (dns_rdataset_isassociated(rdataset)) {
   1238 			dns_rdataset_disassociate(rdataset);
   1239 			if (sigrdataset != NULL &&
   1240 			    dns_rdataset_isassociated(sigrdataset))
   1241 			{
   1242 				dns_rdataset_disassociate(sigrdataset);
   1243 			}
   1244 		}
   1245 		dns_name_copy(zfname, fname);
   1246 		if (dcname != NULL) {
   1247 			dns_name_copy(zfname, dcname);
   1248 		}
   1249 		dns_rdataset_clone(&zrdataset, rdataset);
   1250 		if (sigrdataset != NULL &&
   1251 		    dns_rdataset_isassociated(&zrdataset))
   1252 		{
   1253 			dns_rdataset_clone(&zsigrdataset, sigrdataset);
   1254 		}
   1255 	} else if (try_hints) {
   1256 		/*
   1257 		 * We've found nothing so far, but we have hints.
   1258 		 */
   1259 		result = dns_db_find(view->hints, dns_rootname, NULL,
   1260 				     dns_rdatatype_ns, 0, now, NULL, fname,
   1261 				     rdataset, NULL);
   1262 		if (result != ISC_R_SUCCESS) {
   1263 			/*
   1264 			 * We can't even find the hints for the root
   1265 			 * nameservers!
   1266 			 */
   1267 			if (dns_rdataset_isassociated(rdataset)) {
   1268 				dns_rdataset_disassociate(rdataset);
   1269 			}
   1270 			result = ISC_R_NOTFOUND;
   1271 		} else if (dcname != NULL) {
   1272 			dns_name_copy(fname, dcname);
   1273 		}
   1274 	}
   1275 
   1276 cleanup:
   1277 	if (dns_rdataset_isassociated(&zrdataset)) {
   1278 		dns_rdataset_disassociate(&zrdataset);
   1279 		if (dns_rdataset_isassociated(&zsigrdataset)) {
   1280 			dns_rdataset_disassociate(&zsigrdataset);
   1281 		}
   1282 	}
   1283 	if (db != NULL) {
   1284 		dns_db_detach(&db);
   1285 	}
   1286 	if (zone != NULL) {
   1287 		dns_zone_detach(&zone);
   1288 	}
   1289 
   1290 	return result;
   1291 }
   1292 
   1293 isc_result_t
   1294 dns_viewlist_find(dns_viewlist_t *list, const char *name,
   1295 		  dns_rdataclass_t rdclass, dns_view_t **viewp) {
   1296 	dns_view_t *view;
   1297 
   1298 	REQUIRE(list != NULL);
   1299 
   1300 	for (view = ISC_LIST_HEAD(*list); view != NULL;
   1301 	     view = ISC_LIST_NEXT(view, link))
   1302 	{
   1303 		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass) {
   1304 			break;
   1305 		}
   1306 	}
   1307 	if (view == NULL) {
   1308 		return ISC_R_NOTFOUND;
   1309 	}
   1310 
   1311 	dns_view_attach(view, viewp);
   1312 
   1313 	return ISC_R_SUCCESS;
   1314 }
   1315 
   1316 isc_result_t
   1317 dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name,
   1318 		      bool allclasses, dns_rdataclass_t rdclass,
   1319 		      dns_zone_t **zonep) {
   1320 	dns_view_t *view;
   1321 	isc_result_t result;
   1322 	dns_zone_t *zone1 = NULL, *zone2 = NULL;
   1323 
   1324 	REQUIRE(list != NULL);
   1325 	REQUIRE(zonep != NULL && *zonep == NULL);
   1326 
   1327 	for (view = ISC_LIST_HEAD(*list); view != NULL;
   1328 	     view = ISC_LIST_NEXT(view, link))
   1329 	{
   1330 		dns_zt_t *zonetable = NULL;
   1331 		if (!allclasses && view->rdclass != rdclass) {
   1332 			continue;
   1333 		}
   1334 		rcu_read_lock();
   1335 		zonetable = rcu_dereference(view->zonetable);
   1336 		if (zonetable != NULL) {
   1337 			result = dns_zt_find(zonetable, name, DNS_ZTFIND_EXACT,
   1338 					     (zone1 == NULL) ? &zone1 : &zone2);
   1339 		} else {
   1340 			result = ISC_R_NOTFOUND;
   1341 		}
   1342 		rcu_read_unlock();
   1343 		INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND);
   1344 		if (zone2 != NULL) {
   1345 			dns_zone_detach(&zone1);
   1346 			dns_zone_detach(&zone2);
   1347 			return ISC_R_MULTIPLE;
   1348 		}
   1349 	}
   1350 
   1351 	if (zone1 != NULL) {
   1352 		dns_zone_attach(zone1, zonep);
   1353 		dns_zone_detach(&zone1);
   1354 		return ISC_R_SUCCESS;
   1355 	}
   1356 
   1357 	return ISC_R_NOTFOUND;
   1358 }
   1359 
   1360 isc_result_t
   1361 dns_view_load(dns_view_t *view, bool stop, bool newonly) {
   1362 	isc_result_t result;
   1363 	dns_zt_t *zonetable = NULL;
   1364 
   1365 	REQUIRE(DNS_VIEW_VALID(view));
   1366 
   1367 	rcu_read_lock();
   1368 	zonetable = rcu_dereference(view->zonetable);
   1369 	if (zonetable != NULL) {
   1370 		result = dns_zt_load(zonetable, stop, newonly);
   1371 	} else {
   1372 		result = ISC_R_SUCCESS;
   1373 	}
   1374 	rcu_read_unlock();
   1375 	return result;
   1376 }
   1377 
   1378 isc_result_t
   1379 dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_callback_t *callback,
   1380 		   void *arg) {
   1381 	isc_result_t result;
   1382 	dns_zt_t *zonetable = NULL;
   1383 
   1384 	REQUIRE(DNS_VIEW_VALID(view));
   1385 
   1386 	rcu_read_lock();
   1387 	zonetable = rcu_dereference(view->zonetable);
   1388 	if (zonetable != NULL) {
   1389 		result = dns_zt_asyncload(zonetable, newonly, callback, arg);
   1390 	} else {
   1391 		result = ISC_R_SUCCESS;
   1392 	}
   1393 	rcu_read_unlock();
   1394 	return result;
   1395 }
   1396 
   1397 isc_result_t
   1398 dns_view_gettsig(dns_view_t *view, const dns_name_t *keyname,
   1399 		 dns_tsigkey_t **keyp) {
   1400 	isc_result_t result;
   1401 	REQUIRE(keyp != NULL && *keyp == NULL);
   1402 
   1403 	result = dns_tsigkey_find(keyp, keyname, NULL, view->statickeys);
   1404 	if (result == ISC_R_NOTFOUND) {
   1405 		result = dns_tsigkey_find(keyp, keyname, NULL,
   1406 					  view->dynamickeys);
   1407 	}
   1408 	return result;
   1409 }
   1410 
   1411 isc_result_t
   1412 dns_view_gettransport(dns_view_t *view, const dns_transport_type_t type,
   1413 		      const dns_name_t *name, dns_transport_t **transportp) {
   1414 	REQUIRE(DNS_VIEW_VALID(view));
   1415 	REQUIRE(transportp != NULL && *transportp == NULL);
   1416 
   1417 	dns_transport_t *transport = dns_transport_find(type, name,
   1418 							view->transports);
   1419 	if (transport == NULL) {
   1420 		return ISC_R_NOTFOUND;
   1421 	}
   1422 
   1423 	*transportp = transport;
   1424 	return ISC_R_SUCCESS;
   1425 }
   1426 
   1427 isc_result_t
   1428 dns_view_getpeertsig(dns_view_t *view, const isc_netaddr_t *peeraddr,
   1429 		     dns_tsigkey_t **keyp) {
   1430 	isc_result_t result;
   1431 	dns_name_t *keyname = NULL;
   1432 	dns_peer_t *peer = NULL;
   1433 
   1434 	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
   1435 	if (result != ISC_R_SUCCESS) {
   1436 		return result;
   1437 	}
   1438 
   1439 	result = dns_peer_getkey(peer, &keyname);
   1440 	if (result != ISC_R_SUCCESS) {
   1441 		return result;
   1442 	}
   1443 
   1444 	result = dns_view_gettsig(view, keyname, keyp);
   1445 	return (result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result;
   1446 }
   1447 
   1448 isc_result_t
   1449 dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
   1450 	REQUIRE(DNS_VIEW_VALID(view));
   1451 	REQUIRE(source != NULL);
   1452 
   1453 	return dns_tsig_verify(source, msg, view->statickeys,
   1454 			       view->dynamickeys);
   1455 }
   1456 
   1457 isc_result_t
   1458 dns_view_flushcache(dns_view_t *view, bool fixuponly) {
   1459 	isc_result_t result;
   1460 	dns_adb_t *adb = NULL;
   1461 
   1462 	REQUIRE(DNS_VIEW_VALID(view));
   1463 
   1464 	if (view->cachedb == NULL) {
   1465 		return ISC_R_SUCCESS;
   1466 	}
   1467 	if (!fixuponly) {
   1468 		result = dns_cache_flush(view->cache);
   1469 		if (result != ISC_R_SUCCESS) {
   1470 			return result;
   1471 		}
   1472 	}
   1473 	dns_db_detach(&view->cachedb);
   1474 	dns_cache_attachdb(view->cache, &view->cachedb);
   1475 	if (view->failcache != NULL) {
   1476 		dns_badcache_flush(view->failcache);
   1477 	}
   1478 
   1479 	rcu_read_lock();
   1480 	adb = rcu_dereference(view->adb);
   1481 	if (adb != NULL) {
   1482 		dns_adb_flush(adb);
   1483 	}
   1484 	rcu_read_unlock();
   1485 
   1486 	return ISC_R_SUCCESS;
   1487 }
   1488 
   1489 isc_result_t
   1490 dns_view_flushname(dns_view_t *view, const dns_name_t *name) {
   1491 	return dns_view_flushnode(view, name, false);
   1492 }
   1493 
   1494 isc_result_t
   1495 dns_view_flushnode(dns_view_t *view, const dns_name_t *name, bool tree) {
   1496 	isc_result_t result = ISC_R_SUCCESS;
   1497 	dns_adb_t *adb = NULL;
   1498 
   1499 	REQUIRE(DNS_VIEW_VALID(view));
   1500 
   1501 	if (tree) {
   1502 		rcu_read_lock();
   1503 		adb = rcu_dereference(view->adb);
   1504 		if (adb != NULL) {
   1505 			dns_adb_flushnames(adb, name);
   1506 		}
   1507 		rcu_read_unlock();
   1508 		if (view->failcache != NULL) {
   1509 			dns_badcache_flushtree(view->failcache, name);
   1510 		}
   1511 	} else {
   1512 		rcu_read_lock();
   1513 		adb = rcu_dereference(view->adb);
   1514 		if (adb != NULL) {
   1515 			dns_adb_flushname(adb, name);
   1516 		}
   1517 		rcu_read_unlock();
   1518 		if (view->failcache != NULL) {
   1519 			dns_badcache_flushname(view->failcache, name);
   1520 		}
   1521 	}
   1522 
   1523 	if (view->cache != NULL) {
   1524 		result = dns_cache_flushnode(view->cache, name, tree);
   1525 	}
   1526 
   1527 	return result;
   1528 }
   1529 
   1530 isc_result_t
   1531 dns_view_freezezones(dns_view_t *view, bool value) {
   1532 	isc_result_t result;
   1533 	dns_zt_t *zonetable = NULL;
   1534 
   1535 	REQUIRE(DNS_VIEW_VALID(view));
   1536 
   1537 	rcu_read_lock();
   1538 	zonetable = rcu_dereference(view->zonetable);
   1539 	if (zonetable != NULL) {
   1540 		result = dns_zt_freezezones(zonetable, view, value);
   1541 	} else {
   1542 		result = ISC_R_SUCCESS;
   1543 	}
   1544 	rcu_read_unlock();
   1545 
   1546 	return result;
   1547 }
   1548 
   1549 void
   1550 dns_view_initntatable(dns_view_t *view, isc_loopmgr_t *loopmgr) {
   1551 	REQUIRE(DNS_VIEW_VALID(view));
   1552 	if (view->ntatable_priv != NULL) {
   1553 		dns_ntatable_detach(&view->ntatable_priv);
   1554 	}
   1555 	dns_ntatable_create(view, loopmgr, &view->ntatable_priv);
   1556 }
   1557 
   1558 isc_result_t
   1559 dns_view_getntatable(dns_view_t *view, dns_ntatable_t **ntp) {
   1560 	REQUIRE(DNS_VIEW_VALID(view));
   1561 	REQUIRE(ntp != NULL && *ntp == NULL);
   1562 	if (view->ntatable_priv == NULL) {
   1563 		return ISC_R_NOTFOUND;
   1564 	}
   1565 	dns_ntatable_attach(view->ntatable_priv, ntp);
   1566 	return ISC_R_SUCCESS;
   1567 }
   1568 
   1569 void
   1570 dns_view_initsecroots(dns_view_t *view) {
   1571 	REQUIRE(DNS_VIEW_VALID(view));
   1572 	if (view->secroots_priv != NULL) {
   1573 		dns_keytable_detach(&view->secroots_priv);
   1574 	}
   1575 	dns_keytable_create(view, &view->secroots_priv);
   1576 }
   1577 
   1578 isc_result_t
   1579 dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
   1580 	REQUIRE(DNS_VIEW_VALID(view));
   1581 	REQUIRE(ktp != NULL && *ktp == NULL);
   1582 	if (view->secroots_priv == NULL) {
   1583 		return ISC_R_NOTFOUND;
   1584 	}
   1585 	dns_keytable_attach(view->secroots_priv, ktp);
   1586 	return ISC_R_SUCCESS;
   1587 }
   1588 
   1589 bool
   1590 dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, const dns_name_t *name,
   1591 		   const dns_name_t *anchor) {
   1592 	REQUIRE(DNS_VIEW_VALID(view));
   1593 
   1594 	if (view->ntatable_priv == NULL) {
   1595 		return false;
   1596 	}
   1597 
   1598 	return dns_ntatable_covered(view->ntatable_priv, now, name, anchor);
   1599 }
   1600 
   1601 isc_result_t
   1602 dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
   1603 			isc_stdtime_t now, bool checknta, bool *ntap,
   1604 			bool *secure_domain) {
   1605 	isc_result_t result;
   1606 	bool secure = false;
   1607 	dns_fixedname_t fn;
   1608 	dns_name_t *anchor;
   1609 
   1610 	REQUIRE(DNS_VIEW_VALID(view));
   1611 
   1612 	if (view->secroots_priv == NULL) {
   1613 		return ISC_R_NOTFOUND;
   1614 	}
   1615 
   1616 	anchor = dns_fixedname_initname(&fn);
   1617 
   1618 	result = dns_keytable_issecuredomain(view->secroots_priv, name, anchor,
   1619 					     &secure);
   1620 	if (result != ISC_R_SUCCESS) {
   1621 		return result;
   1622 	}
   1623 
   1624 	SET_IF_NOT_NULL(ntap, false);
   1625 	if (checknta && secure && view->ntatable_priv != NULL &&
   1626 	    dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
   1627 	{
   1628 		if (ntap != NULL) {
   1629 			*ntap = true;
   1630 		}
   1631 		secure = false;
   1632 	}
   1633 
   1634 	*secure_domain = secure;
   1635 	return ISC_R_SUCCESS;
   1636 }
   1637 
   1638 void
   1639 dns_view_untrust(dns_view_t *view, const dns_name_t *keyname,
   1640 		 const dns_rdata_dnskey_t *dnskey) {
   1641 	isc_result_t result;
   1642 	dns_keytable_t *sr = NULL;
   1643 	dns_rdata_dnskey_t tmpkey;
   1644 
   1645 	REQUIRE(DNS_VIEW_VALID(view));
   1646 	REQUIRE(keyname != NULL);
   1647 	REQUIRE(dnskey != NULL);
   1648 
   1649 	result = dns_view_getsecroots(view, &sr);
   1650 	if (result != ISC_R_SUCCESS) {
   1651 		return;
   1652 	}
   1653 
   1654 	/*
   1655 	 * Clear the revoke bit, if set, so that the key will match what's
   1656 	 * in secroots now.
   1657 	 */
   1658 	tmpkey = *dnskey;
   1659 	tmpkey.flags &= ~DNS_KEYFLAG_REVOKE;
   1660 
   1661 	result = dns_keytable_deletekey(sr, keyname, &tmpkey);
   1662 	if (result == ISC_R_SUCCESS) {
   1663 		/*
   1664 		 * If key was found in secroots, then it was a
   1665 		 * configured trust anchor, and we want to fail
   1666 		 * secure. If there are no other configured keys,
   1667 		 * then leave a null key so that we can't validate
   1668 		 * anymore.
   1669 		 */
   1670 		dns_keytable_marksecure(sr, keyname);
   1671 	}
   1672 
   1673 	dns_keytable_detach(&sr);
   1674 }
   1675 
   1676 bool
   1677 dns_view_istrusted(dns_view_t *view, const dns_name_t *keyname,
   1678 		   const dns_rdata_dnskey_t *dnskey) {
   1679 	isc_result_t result;
   1680 	dns_keytable_t *sr = NULL;
   1681 	dns_keynode_t *knode = NULL;
   1682 	bool answer = false;
   1683 	dns_rdataset_t dsset;
   1684 
   1685 	REQUIRE(DNS_VIEW_VALID(view));
   1686 	REQUIRE(keyname != NULL);
   1687 	REQUIRE(dnskey != NULL);
   1688 
   1689 	result = dns_view_getsecroots(view, &sr);
   1690 	if (result != ISC_R_SUCCESS) {
   1691 		return false;
   1692 	}
   1693 
   1694 	dns_rdataset_init(&dsset);
   1695 	result = dns_keytable_find(sr, keyname, &knode);
   1696 	if (result == ISC_R_SUCCESS) {
   1697 		if (dns_keynode_dsset(knode, &dsset)) {
   1698 			dns_rdata_t rdata = DNS_RDATA_INIT;
   1699 			unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
   1700 			dns_rdata_dnskey_t tmpkey = *dnskey;
   1701 			dns_rdata_ds_t ds;
   1702 			isc_buffer_t b;
   1703 			dns_rdataclass_t rdclass = tmpkey.common.rdclass;
   1704 
   1705 			/*
   1706 			 * Clear the revoke bit, if set, so that the key
   1707 			 * will match what's in secroots now.
   1708 			 */
   1709 			tmpkey.flags &= ~DNS_KEYFLAG_REVOKE;
   1710 
   1711 			isc_buffer_init(&b, data, sizeof(data));
   1712 			result = dns_rdata_fromstruct(&rdata, rdclass,
   1713 						      dns_rdatatype_dnskey,
   1714 						      &tmpkey, &b);
   1715 			if (result != ISC_R_SUCCESS) {
   1716 				goto finish;
   1717 			}
   1718 
   1719 			result = dns_ds_fromkeyrdata(keyname, &rdata,
   1720 						     DNS_DSDIGEST_SHA256,
   1721 						     digest, &ds);
   1722 			if (result != ISC_R_SUCCESS) {
   1723 				goto finish;
   1724 			}
   1725 
   1726 			dns_rdata_reset(&rdata);
   1727 			isc_buffer_init(&b, data, sizeof(data));
   1728 			result = dns_rdata_fromstruct(
   1729 				&rdata, rdclass, dns_rdatatype_ds, &ds, &b);
   1730 			if (result != ISC_R_SUCCESS) {
   1731 				goto finish;
   1732 			}
   1733 
   1734 			result = dns_rdataset_first(&dsset);
   1735 			while (result == ISC_R_SUCCESS) {
   1736 				dns_rdata_t this = DNS_RDATA_INIT;
   1737 				dns_rdataset_current(&dsset, &this);
   1738 				if (dns_rdata_compare(&rdata, &this) == 0) {
   1739 					answer = true;
   1740 					break;
   1741 				}
   1742 				result = dns_rdataset_next(&dsset);
   1743 			}
   1744 		}
   1745 	}
   1746 
   1747 finish:
   1748 	if (dns_rdataset_isassociated(&dsset)) {
   1749 		dns_rdataset_disassociate(&dsset);
   1750 	}
   1751 	if (knode != NULL) {
   1752 		dns_keynode_detach(&knode);
   1753 	}
   1754 	dns_keytable_detach(&sr);
   1755 	return answer;
   1756 }
   1757 
   1758 /*
   1759  * Create path to a directory and a filename constructed from viewname.
   1760  * This is a front-end to isc_file_sanitize(), allowing backward
   1761  * compatibility to older versions when a file couldn't be expected
   1762  * to be in the specified directory but might be in the current working
   1763  * directory instead.
   1764  *
   1765  * It first tests for the existence of a file <viewname>.<suffix> in
   1766  * 'directory'. If the file does not exist, it checks again in the
   1767  * current working directory. If it does not exist there either,
   1768  * return the path inside the directory.
   1769  *
   1770  * Returns ISC_R_SUCCESS if a path to an existing file is found or
   1771  * a new path is created; returns ISC_R_NOSPACE if the path won't
   1772  * fit in 'buflen'.
   1773  */
   1774 
   1775 static isc_result_t
   1776 nz_legacy(const char *directory, const char *viewname, const char *suffix,
   1777 	  char *buffer, size_t buflen) {
   1778 	isc_result_t result;
   1779 	char newbuf[PATH_MAX];
   1780 
   1781 	result = isc_file_sanitize(directory, viewname, suffix, buffer, buflen);
   1782 	if (result != ISC_R_SUCCESS) {
   1783 		return result;
   1784 	} else if (directory == NULL || isc_file_exists(buffer)) {
   1785 		return ISC_R_SUCCESS;
   1786 	} else {
   1787 		/* Save buffer */
   1788 		strlcpy(newbuf, buffer, sizeof(newbuf));
   1789 	}
   1790 
   1791 	/*
   1792 	 * It isn't in the specified directory; check CWD.
   1793 	 */
   1794 	result = isc_file_sanitize(NULL, viewname, suffix, buffer, buflen);
   1795 	if (result != ISC_R_SUCCESS || isc_file_exists(buffer)) {
   1796 		return result;
   1797 	}
   1798 
   1799 	/*
   1800 	 * File does not exist in either 'directory' or CWD,
   1801 	 * so use the path in 'directory'.
   1802 	 */
   1803 	strlcpy(buffer, newbuf, buflen);
   1804 	return ISC_R_SUCCESS;
   1805 }
   1806 
   1807 isc_result_t
   1808 dns_view_setnewzones(dns_view_t *view, bool allow, void *cfgctx,
   1809 		     void (*cfg_destroy)(void **), uint64_t mapsize) {
   1810 	isc_result_t result = ISC_R_SUCCESS;
   1811 	char buffer[1024];
   1812 #ifdef HAVE_LMDB
   1813 	MDB_env *env = NULL;
   1814 	int status;
   1815 #endif /* ifdef HAVE_LMDB */
   1816 
   1817 #ifndef HAVE_LMDB
   1818 	UNUSED(mapsize);
   1819 #endif /* ifndef HAVE_LMDB */
   1820 
   1821 	REQUIRE(DNS_VIEW_VALID(view));
   1822 	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
   1823 
   1824 	if (view->new_zone_file != NULL) {
   1825 		isc_mem_free(view->mctx, view->new_zone_file);
   1826 		view->new_zone_file = NULL;
   1827 	}
   1828 
   1829 #ifdef HAVE_LMDB
   1830 	if (view->new_zone_dbenv != NULL) {
   1831 		mdb_env_close((MDB_env *)view->new_zone_dbenv);
   1832 		view->new_zone_dbenv = NULL;
   1833 	}
   1834 
   1835 	if (view->new_zone_db != NULL) {
   1836 		isc_mem_free(view->mctx, view->new_zone_db);
   1837 		view->new_zone_db = NULL;
   1838 	}
   1839 #endif /* HAVE_LMDB */
   1840 
   1841 	if (view->new_zone_config != NULL) {
   1842 		view->cfg_destroy(&view->new_zone_config);
   1843 		view->cfg_destroy = NULL;
   1844 	}
   1845 
   1846 	if (!allow) {
   1847 		return ISC_R_SUCCESS;
   1848 	}
   1849 
   1850 	CHECK(nz_legacy(view->new_zone_dir, view->name, "nzf", buffer,
   1851 			sizeof(buffer)));
   1852 
   1853 	view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
   1854 
   1855 #ifdef HAVE_LMDB
   1856 	CHECK(nz_legacy(view->new_zone_dir, view->name, "nzd", buffer,
   1857 			sizeof(buffer)));
   1858 
   1859 	view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
   1860 
   1861 	status = mdb_env_create(&env);
   1862 	if (status != MDB_SUCCESS) {
   1863 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1864 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   1865 			      "mdb_env_create failed: %s",
   1866 			      mdb_strerror(status));
   1867 		CHECK(ISC_R_FAILURE);
   1868 	}
   1869 
   1870 	if (mapsize != 0ULL) {
   1871 		status = mdb_env_set_mapsize(env, mapsize);
   1872 		if (status != MDB_SUCCESS) {
   1873 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1874 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   1875 				      "mdb_env_set_mapsize failed: %s",
   1876 				      mdb_strerror(status));
   1877 			CHECK(ISC_R_FAILURE);
   1878 		}
   1879 		view->new_zone_mapsize = mapsize;
   1880 	}
   1881 
   1882 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
   1883 	if (status != MDB_SUCCESS) {
   1884 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1885 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
   1886 			      "mdb_env_open of '%s' failed: %s",
   1887 			      view->new_zone_db, mdb_strerror(status));
   1888 		CHECK(ISC_R_FAILURE);
   1889 	}
   1890 
   1891 	view->new_zone_dbenv = env;
   1892 	env = NULL;
   1893 #endif /* HAVE_LMDB */
   1894 
   1895 	view->new_zone_config = cfgctx;
   1896 	view->cfg_destroy = cfg_destroy;
   1897 
   1898 cleanup:
   1899 	if (result != ISC_R_SUCCESS) {
   1900 		if (view->new_zone_file != NULL) {
   1901 			isc_mem_free(view->mctx, view->new_zone_file);
   1902 			view->new_zone_file = NULL;
   1903 		}
   1904 
   1905 #ifdef HAVE_LMDB
   1906 		if (view->new_zone_db != NULL) {
   1907 			isc_mem_free(view->mctx, view->new_zone_db);
   1908 			view->new_zone_db = NULL;
   1909 		}
   1910 		if (env != NULL) {
   1911 			mdb_env_close(env);
   1912 		}
   1913 #endif /* HAVE_LMDB */
   1914 		view->new_zone_config = NULL;
   1915 		view->cfg_destroy = NULL;
   1916 	}
   1917 
   1918 	return result;
   1919 }
   1920 
   1921 void
   1922 dns_view_setnewzonedir(dns_view_t *view, const char *dir) {
   1923 	REQUIRE(DNS_VIEW_VALID(view));
   1924 
   1925 	if (view->new_zone_dir != NULL) {
   1926 		isc_mem_free(view->mctx, view->new_zone_dir);
   1927 		view->new_zone_dir = NULL;
   1928 	}
   1929 
   1930 	if (dir == NULL) {
   1931 		return;
   1932 	}
   1933 
   1934 	view->new_zone_dir = isc_mem_strdup(view->mctx, dir);
   1935 }
   1936 
   1937 const char *
   1938 dns_view_getnewzonedir(dns_view_t *view) {
   1939 	REQUIRE(DNS_VIEW_VALID(view));
   1940 
   1941 	return view->new_zone_dir;
   1942 }
   1943 
   1944 isc_result_t
   1945 dns_view_searchdlz(dns_view_t *view, const dns_name_t *name,
   1946 		   unsigned int minlabels, dns_clientinfomethods_t *methods,
   1947 		   dns_clientinfo_t *clientinfo, dns_db_t **dbp) {
   1948 	dns_fixedname_t fname;
   1949 	dns_name_t *zonename;
   1950 	unsigned int namelabels;
   1951 	unsigned int i;
   1952 	isc_result_t result;
   1953 	dns_dlzfindzone_t findzone;
   1954 	dns_dlzdb_t *dlzdb;
   1955 	dns_db_t *db, *best = NULL;
   1956 
   1957 	/*
   1958 	 * Performs checks to make sure data is as we expect it to be.
   1959 	 */
   1960 	REQUIRE(DNS_VIEW_VALID(view));
   1961 	REQUIRE(name != NULL);
   1962 	REQUIRE(dbp != NULL && *dbp == NULL);
   1963 
   1964 	/* setup a "fixed" dns name */
   1965 	zonename = dns_fixedname_initname(&fname);
   1966 
   1967 	/* count the number of labels in the name */
   1968 	namelabels = dns_name_countlabels(name);
   1969 
   1970 	for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); dlzdb != NULL;
   1971 	     dlzdb = ISC_LIST_NEXT(dlzdb, link))
   1972 	{
   1973 		REQUIRE(DNS_DLZ_VALID(dlzdb));
   1974 
   1975 		/*
   1976 		 * loop through starting with the longest domain name and
   1977 		 * trying shorter names portions of the name until we find a
   1978 		 * match, have an error, or are below the 'minlabels'
   1979 		 * threshold.  minlabels is 0, if neither the standard
   1980 		 * database nor any previous DLZ database had a zone name
   1981 		 * match. Otherwise minlabels is the number of labels
   1982 		 * in that name.  We need to beat that for a "better"
   1983 		 * match for this DLZ database to be authoritative.
   1984 		 */
   1985 		for (i = namelabels; i > minlabels && i > 1; i--) {
   1986 			if (i == namelabels) {
   1987 				dns_name_copy(name, zonename);
   1988 			} else {
   1989 				dns_name_split(name, i, NULL, zonename);
   1990 			}
   1991 
   1992 			/* ask SDLZ driver if the zone is supported */
   1993 			db = NULL;
   1994 			findzone = dlzdb->implementation->methods->findzone;
   1995 			result = (*findzone)(dlzdb->implementation->driverarg,
   1996 					     dlzdb->dbdata, dlzdb->mctx,
   1997 					     view->rdclass, zonename, methods,
   1998 					     clientinfo, &db);
   1999 
   2000 			if (result != ISC_R_NOTFOUND) {
   2001 				if (best != NULL) {
   2002 					dns_db_detach(&best);
   2003 				}
   2004 				if (result == ISC_R_SUCCESS) {
   2005 					INSIST(db != NULL);
   2006 					dns_db_attach(db, &best);
   2007 					dns_db_detach(&db);
   2008 					minlabels = i;
   2009 				} else {
   2010 					if (db != NULL) {
   2011 						dns_db_detach(&db);
   2012 					}
   2013 					break;
   2014 				}
   2015 			} else if (db != NULL) {
   2016 				dns_db_detach(&db);
   2017 			}
   2018 		}
   2019 	}
   2020 
   2021 	if (best != NULL) {
   2022 		dns_db_attach(best, dbp);
   2023 		dns_db_detach(&best);
   2024 		return ISC_R_SUCCESS;
   2025 	}
   2026 
   2027 	return ISC_R_NOTFOUND;
   2028 }
   2029 
   2030 uint32_t
   2031 dns_view_getfailttl(dns_view_t *view) {
   2032 	REQUIRE(DNS_VIEW_VALID(view));
   2033 	return view->fail_ttl;
   2034 }
   2035 
   2036 void
   2037 dns_view_setfailttl(dns_view_t *view, uint32_t fail_ttl) {
   2038 	REQUIRE(DNS_VIEW_VALID(view));
   2039 	view->fail_ttl = fail_ttl;
   2040 }
   2041 
   2042 isc_result_t
   2043 dns_view_saventa(dns_view_t *view) {
   2044 	isc_result_t result;
   2045 	bool removefile = false;
   2046 	dns_ntatable_t *ntatable = NULL;
   2047 	FILE *fp = NULL;
   2048 
   2049 	REQUIRE(DNS_VIEW_VALID(view));
   2050 
   2051 	if (view->nta_lifetime == 0) {
   2052 		return ISC_R_SUCCESS;
   2053 	}
   2054 
   2055 	/* Open NTA save file for overwrite. */
   2056 	CHECK(isc_stdio_open(view->nta_file, "w", &fp));
   2057 
   2058 	result = dns_view_getntatable(view, &ntatable);
   2059 	if (result == ISC_R_NOTFOUND) {
   2060 		removefile = true;
   2061 		result = ISC_R_SUCCESS;
   2062 		goto cleanup;
   2063 	} else {
   2064 		CHECK(result);
   2065 	}
   2066 
   2067 	result = dns_ntatable_save(ntatable, fp);
   2068 	if (result == ISC_R_NOTFOUND) {
   2069 		removefile = true;
   2070 		result = ISC_R_SUCCESS;
   2071 	} else if (result == ISC_R_SUCCESS) {
   2072 		result = isc_stdio_close(fp);
   2073 		fp = NULL;
   2074 	}
   2075 
   2076 cleanup:
   2077 	if (ntatable != NULL) {
   2078 		dns_ntatable_detach(&ntatable);
   2079 	}
   2080 
   2081 	if (fp != NULL) {
   2082 		(void)isc_stdio_close(fp);
   2083 	}
   2084 
   2085 	/* Don't leave half-baked NTA save files lying around. */
   2086 	if (result != ISC_R_SUCCESS || removefile) {
   2087 		(void)isc_file_remove(view->nta_file);
   2088 	}
   2089 
   2090 	return result;
   2091 }
   2092 
   2093 #define TSTR(t) ((t).value.as_textregion.base)
   2094 #define TLEN(t) ((t).value.as_textregion.length)
   2095 
   2096 isc_result_t
   2097 dns_view_loadnta(dns_view_t *view) {
   2098 	isc_result_t result;
   2099 	dns_ntatable_t *ntatable = NULL;
   2100 	isc_lex_t *lex = NULL;
   2101 	isc_token_t token;
   2102 	isc_stdtime_t now = isc_stdtime_now();
   2103 
   2104 	REQUIRE(DNS_VIEW_VALID(view));
   2105 
   2106 	if (view->nta_lifetime == 0) {
   2107 		return ISC_R_SUCCESS;
   2108 	}
   2109 
   2110 	isc_lex_create(view->mctx, 1025, &lex);
   2111 	CHECK(isc_lex_openfile(lex, view->nta_file));
   2112 	CHECK(dns_view_getntatable(view, &ntatable));
   2113 
   2114 	for (;;) {
   2115 		int options = (ISC_LEXOPT_EOL | ISC_LEXOPT_EOF);
   2116 		char *name, *type, *timestamp;
   2117 		size_t len;
   2118 		dns_fixedname_t fn;
   2119 		const dns_name_t *ntaname;
   2120 		isc_buffer_t b;
   2121 		isc_stdtime_t t;
   2122 		bool forced;
   2123 
   2124 		CHECK(isc_lex_gettoken(lex, options, &token));
   2125 		if (token.type == isc_tokentype_eof) {
   2126 			break;
   2127 		} else if (token.type != isc_tokentype_string) {
   2128 			CHECK(ISC_R_UNEXPECTEDTOKEN);
   2129 		}
   2130 		name = TSTR(token);
   2131 		len = TLEN(token);
   2132 
   2133 		if (strcmp(name, ".") == 0) {
   2134 			ntaname = dns_rootname;
   2135 		} else {
   2136 			dns_name_t *fname;
   2137 			fname = dns_fixedname_initname(&fn);
   2138 
   2139 			isc_buffer_init(&b, name, (unsigned int)len);
   2140 			isc_buffer_add(&b, (unsigned int)len);
   2141 			CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0,
   2142 						NULL));
   2143 			ntaname = fname;
   2144 		}
   2145 
   2146 		CHECK(isc_lex_gettoken(lex, options, &token));
   2147 		if (token.type != isc_tokentype_string) {
   2148 			CHECK(ISC_R_UNEXPECTEDTOKEN);
   2149 		}
   2150 		type = TSTR(token);
   2151 
   2152 		if (strcmp(type, "regular") == 0) {
   2153 			forced = false;
   2154 		} else if (strcmp(type, "forced") == 0) {
   2155 			forced = true;
   2156 		} else {
   2157 			CHECK(ISC_R_UNEXPECTEDTOKEN);
   2158 		}
   2159 
   2160 		CHECK(isc_lex_gettoken(lex, options, &token));
   2161 		if (token.type != isc_tokentype_string) {
   2162 			CHECK(ISC_R_UNEXPECTEDTOKEN);
   2163 		}
   2164 		timestamp = TSTR(token);
   2165 		CHECK(dns_time32_fromtext(timestamp, &t));
   2166 
   2167 		CHECK(isc_lex_gettoken(lex, options, &token));
   2168 		if (token.type != isc_tokentype_eol &&
   2169 		    token.type != isc_tokentype_eof)
   2170 		{
   2171 			CHECK(ISC_R_UNEXPECTEDTOKEN);
   2172 		}
   2173 
   2174 		if (now <= t) {
   2175 			if (t > (now + 604800)) {
   2176 				t = now + 604800;
   2177 			}
   2178 
   2179 			(void)dns_ntatable_add(ntatable, ntaname, forced, 0, t);
   2180 		} else {
   2181 			char nb[DNS_NAME_FORMATSIZE];
   2182 			dns_name_format(ntaname, nb, sizeof(nb));
   2183 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2184 				      DNS_LOGMODULE_NTA, ISC_LOG_INFO,
   2185 				      "ignoring expired NTA at %s", nb);
   2186 		}
   2187 	}
   2188 
   2189 cleanup:
   2190 	if (ntatable != NULL) {
   2191 		dns_ntatable_detach(&ntatable);
   2192 	}
   2193 
   2194 	if (lex != NULL) {
   2195 		isc_lex_close(lex);
   2196 		isc_lex_destroy(&lex);
   2197 	}
   2198 
   2199 	return result;
   2200 }
   2201 
   2202 void
   2203 dns_view_setviewcommit(dns_view_t *view) {
   2204 	dns_zone_t *redirect = NULL, *managed_keys = NULL;
   2205 	dns_zt_t *zonetable = NULL;
   2206 
   2207 	REQUIRE(DNS_VIEW_VALID(view));
   2208 
   2209 	LOCK(&view->lock);
   2210 
   2211 	if (view->redirect != NULL) {
   2212 		dns_zone_attach(view->redirect, &redirect);
   2213 	}
   2214 	if (view->managed_keys != NULL) {
   2215 		dns_zone_attach(view->managed_keys, &managed_keys);
   2216 	}
   2217 
   2218 	UNLOCK(&view->lock);
   2219 
   2220 	rcu_read_lock();
   2221 	zonetable = rcu_dereference(view->zonetable);
   2222 	if (zonetable != NULL) {
   2223 		dns_zt_setviewcommit(zonetable);
   2224 	}
   2225 	rcu_read_unlock();
   2226 
   2227 	if (redirect != NULL) {
   2228 		dns_zone_setviewcommit(redirect);
   2229 		dns_zone_detach(&redirect);
   2230 	}
   2231 	if (managed_keys != NULL) {
   2232 		dns_zone_setviewcommit(managed_keys);
   2233 		dns_zone_detach(&managed_keys);
   2234 	}
   2235 }
   2236 
   2237 void
   2238 dns_view_setviewrevert(dns_view_t *view) {
   2239 	dns_zone_t *redirect = NULL, *managed_keys = NULL;
   2240 	dns_zt_t *zonetable = NULL;
   2241 
   2242 	REQUIRE(DNS_VIEW_VALID(view));
   2243 
   2244 	/*
   2245 	 * dns_zt_setviewrevert() attempts to lock this view, so we must
   2246 	 * release the lock.
   2247 	 */
   2248 	LOCK(&view->lock);
   2249 	if (view->redirect != NULL) {
   2250 		dns_zone_attach(view->redirect, &redirect);
   2251 	}
   2252 	if (view->managed_keys != NULL) {
   2253 		dns_zone_attach(view->managed_keys, &managed_keys);
   2254 	}
   2255 	UNLOCK(&view->lock);
   2256 
   2257 	if (redirect != NULL) {
   2258 		dns_zone_setviewrevert(redirect);
   2259 		dns_zone_detach(&redirect);
   2260 	}
   2261 	if (managed_keys != NULL) {
   2262 		dns_zone_setviewrevert(managed_keys);
   2263 		dns_zone_detach(&managed_keys);
   2264 	}
   2265 	rcu_read_lock();
   2266 	zonetable = rcu_dereference(view->zonetable);
   2267 	if (zonetable != NULL) {
   2268 		dns_zt_setviewrevert(zonetable);
   2269 	}
   2270 	rcu_read_unlock();
   2271 }
   2272 
   2273 bool
   2274 dns_view_staleanswerenabled(dns_view_t *view) {
   2275 	uint32_t stale_ttl = 0;
   2276 	bool result = false;
   2277 
   2278 	REQUIRE(DNS_VIEW_VALID(view));
   2279 
   2280 	if (dns_db_getservestalettl(view->cachedb, &stale_ttl) != ISC_R_SUCCESS)
   2281 	{
   2282 		return false;
   2283 	}
   2284 	if (stale_ttl > 0) {
   2285 		if (view->staleanswersok == dns_stale_answer_yes) {
   2286 			result = true;
   2287 		} else if (view->staleanswersok == dns_stale_answer_conf) {
   2288 			result = view->staleanswersenable;
   2289 		}
   2290 	}
   2291 
   2292 	return result;
   2293 }
   2294 
   2295 void
   2296 dns_view_flushonshutdown(dns_view_t *view, bool flush) {
   2297 	REQUIRE(DNS_VIEW_VALID(view));
   2298 
   2299 	view->flush = flush;
   2300 }
   2301 
   2302 void
   2303 dns_view_sfd_add(dns_view_t *view, const dns_name_t *name) {
   2304 	isc_result_t result;
   2305 
   2306 	REQUIRE(DNS_VIEW_VALID(view));
   2307 
   2308 	result = dns_nametree_add(view->sfd, name, 0);
   2309 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2310 }
   2311 
   2312 void
   2313 dns_view_sfd_del(dns_view_t *view, const dns_name_t *name) {
   2314 	REQUIRE(DNS_VIEW_VALID(view));
   2315 
   2316 	dns_nametree_delete(view->sfd, name);
   2317 }
   2318 
   2319 void
   2320 dns_view_sfd_find(dns_view_t *view, const dns_name_t *name,
   2321 		  dns_name_t *foundname) {
   2322 	REQUIRE(DNS_VIEW_VALID(view));
   2323 
   2324 	if (!dns_nametree_covered(view->sfd, name, foundname, 0)) {
   2325 		dns_name_copy(dns_rootname, foundname);
   2326 	}
   2327 }
   2328 
   2329 isc_result_t
   2330 dns_view_getresolver(dns_view_t *view, dns_resolver_t **resolverp) {
   2331 	isc_result_t result;
   2332 	REQUIRE(DNS_VIEW_VALID(view));
   2333 	REQUIRE(resolverp != NULL && *resolverp == NULL);
   2334 	LOCK(&view->lock);
   2335 	if (view->resolver != NULL) {
   2336 		dns_resolver_attach(view->resolver, resolverp);
   2337 		result = ISC_R_SUCCESS;
   2338 	} else {
   2339 		result = ISC_R_SHUTTINGDOWN;
   2340 	}
   2341 	UNLOCK(&view->lock);
   2342 	return result;
   2343 }
   2344 
   2345 void
   2346 dns_view_setmaxrrperset(dns_view_t *view, uint32_t value) {
   2347 	REQUIRE(DNS_VIEW_VALID(view));
   2348 	view->maxrrperset = value;
   2349 	if (view->cache != NULL) {
   2350 		dns_cache_setmaxrrperset(view->cache, value);
   2351 	}
   2352 }
   2353 
   2354 void
   2355 dns_view_setmaxtypepername(dns_view_t *view, uint32_t value) {
   2356 	REQUIRE(DNS_VIEW_VALID(view));
   2357 	view->maxtypepername = value;
   2358 	if (view->cache != NULL) {
   2359 		dns_cache_setmaxtypepername(view->cache, value);
   2360 	}
   2361 }
   2362 
   2363 void
   2364 dns_view_setudpsize(dns_view_t *view, uint16_t udpsize) {
   2365 	REQUIRE(DNS_VIEW_VALID(view));
   2366 	view->udpsize = udpsize;
   2367 }
   2368 
   2369 uint16_t
   2370 dns_view_getudpsize(dns_view_t *view) {
   2371 	REQUIRE(DNS_VIEW_VALID(view));
   2372 	return view->udpsize;
   2373 }
   2374 
   2375 dns_dispatchmgr_t *
   2376 dns_view_getdispatchmgr(dns_view_t *view) {
   2377 	REQUIRE(DNS_VIEW_VALID(view));
   2378 
   2379 	rcu_read_lock();
   2380 	dns_dispatchmgr_t *dispatchmgr = rcu_dereference(view->dispatchmgr);
   2381 	if (dispatchmgr != NULL) {
   2382 		dns_dispatchmgr_ref(dispatchmgr);
   2383 	}
   2384 	rcu_read_unlock();
   2385 
   2386 	return dispatchmgr;
   2387 }
   2388 
   2389 isc_result_t
   2390 dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype,
   2391 		       const dns_name_t *keyname, isc_buffer_t *databuf) {
   2392 	isc_result_t result;
   2393 	dns_name_t *name = UNCONST(keyname);
   2394 	char rdatabuf[DST_KEY_MAXSIZE];
   2395 	unsigned char digest[ISC_MAX_MD_SIZE];
   2396 	dns_rdata_ds_t ds;
   2397 	dns_rdata_t rdata;
   2398 	isc_buffer_t b;
   2399 
   2400 	REQUIRE(DNS_VIEW_VALID(view));
   2401 	REQUIRE(view->rdclass == dns_rdataclass_in);
   2402 
   2403 	if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
   2404 		result = ISC_R_NOTIMPLEMENTED;
   2405 		goto cleanup;
   2406 	}
   2407 
   2408 	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
   2409 	dns_rdata_init(&rdata);
   2410 	isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
   2411 	CHECK(dns_rdata_fromwire(&rdata, view->rdclass, rdtype, databuf,
   2412 				 DNS_DECOMPRESS_NEVER, &b));
   2413 
   2414 	if (rdtype == dns_rdatatype_ds) {
   2415 		CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
   2416 	} else {
   2417 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
   2418 					  digest, &ds));
   2419 	}
   2420 
   2421 	CHECK(dns_keytable_add(view->secroots_priv, false, false, name, &ds,
   2422 			       NULL, NULL));
   2423 
   2424 cleanup:
   2425 	return result;
   2426 }
   2427 
   2428 isc_result_t
   2429 dns_view_apply(dns_view_t *view, bool stop, isc_result_t *sub,
   2430 	       isc_result_t (*action)(dns_zone_t *, void *), void *uap) {
   2431 	isc_result_t result;
   2432 	dns_zt_t *zonetable = NULL;
   2433 
   2434 	REQUIRE(DNS_VIEW_VALID(view));
   2435 
   2436 	rcu_read_lock();
   2437 	zonetable = rcu_dereference(view->zonetable);
   2438 	if (zonetable != NULL) {
   2439 		result = dns_zt_apply(zonetable, stop, sub, action, uap);
   2440 	} else {
   2441 		result = ISC_R_SHUTTINGDOWN;
   2442 	}
   2443 	rcu_read_unlock();
   2444 	return result;
   2445 }
   2446 
   2447 void
   2448 dns_view_getadb(dns_view_t *view, dns_adb_t **adbp) {
   2449 	dns_adb_t *adb = NULL;
   2450 
   2451 	REQUIRE(DNS_VIEW_VALID(view));
   2452 	REQUIRE(adbp != NULL && *adbp == NULL);
   2453 
   2454 	rcu_read_lock();
   2455 	adb = rcu_dereference(view->adb);
   2456 	if (adb != NULL) {
   2457 		dns_adb_attach(adb, adbp);
   2458 	}
   2459 	rcu_read_unlock();
   2460 }
   2461 
   2462 void
   2463 dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts) {
   2464 	REQUIRE(DNS_VIEW_VALID(view));
   2465 	REQUIRE(max_restarts > 0);
   2466 
   2467 	view->max_restarts = max_restarts;
   2468 }
   2469 
   2470 void
   2471 dns_view_setmaxqueries(dns_view_t *view, uint16_t max_queries) {
   2472 	REQUIRE(DNS_VIEW_VALID(view));
   2473 	REQUIRE(max_queries > 0);
   2474 
   2475 	view->max_queries = max_queries;
   2476 }
   2477