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