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