view.c revision 224092
1135446Strhodes/*
2224092Sdougb * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2003  Internet Software Consortium.
4135446Strhodes *
5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18224092Sdougb/* $Id: view.c,v 1.178 2011-01-13 09:53:04 marka Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24224092Sdougb#include <isc/file.h>
25135446Strhodes#include <isc/hash.h>
26224092Sdougb#include <isc/print.h>
27224092Sdougb#include <isc/sha2.h>
28193149Sdougb#include <isc/stats.h>
29193149Sdougb#include <isc/string.h>		/* Required for HP/UX (and others?) */
30135446Strhodes#include <isc/task.h>
31135446Strhodes#include <isc/util.h>
32135446Strhodes
33170222Sdougb#include <dns/acache.h>
34135446Strhodes#include <dns/acl.h>
35135446Strhodes#include <dns/adb.h>
36135446Strhodes#include <dns/cache.h>
37135446Strhodes#include <dns/db.h>
38170222Sdougb#include <dns/dlz.h>
39224092Sdougb#ifdef BIND9
40224092Sdougb#include <dns/dns64.h>
41224092Sdougb#endif
42224092Sdougb#include <dns/dnssec.h>
43135446Strhodes#include <dns/events.h>
44135446Strhodes#include <dns/forward.h>
45135446Strhodes#include <dns/keytable.h>
46224092Sdougb#include <dns/keyvalues.h>
47135446Strhodes#include <dns/master.h>
48135446Strhodes#include <dns/masterdump.h>
49135446Strhodes#include <dns/order.h>
50135446Strhodes#include <dns/peer.h>
51224092Sdougb#include <dns/rbt.h>
52135446Strhodes#include <dns/rdataset.h>
53135446Strhodes#include <dns/request.h>
54135446Strhodes#include <dns/resolver.h>
55135446Strhodes#include <dns/result.h>
56224092Sdougb#include <dns/rpz.h>
57193149Sdougb#include <dns/stats.h>
58135446Strhodes#include <dns/tsig.h>
59135446Strhodes#include <dns/zone.h>
60135446Strhodes#include <dns/zt.h>
61135446Strhodes
62135446Strhodes#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
63135446Strhodes#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
64135446Strhodes#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
65135446Strhodes
66135446Strhodes#define DNS_VIEW_DELONLYHASH 111
67135446Strhodes
68135446Strhodesstatic void resolver_shutdown(isc_task_t *task, isc_event_t *event);
69135446Strhodesstatic void adb_shutdown(isc_task_t *task, isc_event_t *event);
70135446Strhodesstatic void req_shutdown(isc_task_t *task, isc_event_t *event);
71135446Strhodes
72135446Strhodesisc_result_t
73135446Strhodesdns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
74135446Strhodes		const char *name, dns_view_t **viewp)
75135446Strhodes{
76135446Strhodes	dns_view_t *view;
77135446Strhodes	isc_result_t result;
78135446Strhodes
79135446Strhodes	/*
80135446Strhodes	 * Create a view.
81135446Strhodes	 */
82135446Strhodes
83135446Strhodes	REQUIRE(name != NULL);
84135446Strhodes	REQUIRE(viewp != NULL && *viewp == NULL);
85135446Strhodes
86135446Strhodes	view = isc_mem_get(mctx, sizeof(*view));
87135446Strhodes	if (view == NULL)
88135446Strhodes		return (ISC_R_NOMEMORY);
89135446Strhodes	view->name = isc_mem_strdup(mctx, name);
90135446Strhodes	if (view->name == NULL) {
91135446Strhodes		result = ISC_R_NOMEMORY;
92135446Strhodes		goto cleanup_view;
93135446Strhodes	}
94135446Strhodes	result = isc_mutex_init(&view->lock);
95170222Sdougb	if (result != ISC_R_SUCCESS)
96135446Strhodes		goto cleanup_name;
97170222Sdougb
98224092Sdougb#ifdef BIND9
99135446Strhodes	view->zonetable = NULL;
100135446Strhodes	result = dns_zt_create(mctx, rdclass, &view->zonetable);
101135446Strhodes	if (result != ISC_R_SUCCESS) {
102135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
103135446Strhodes				 "dns_zt_create() failed: %s",
104135446Strhodes				 isc_result_totext(result));
105135446Strhodes		result = ISC_R_UNEXPECTED;
106135446Strhodes		goto cleanup_mutex;
107135446Strhodes	}
108224092Sdougb#endif
109224092Sdougb	view->secroots_priv = NULL;
110135446Strhodes	view->fwdtable = NULL;
111135446Strhodes	result = dns_fwdtable_create(mctx, &view->fwdtable);
112135446Strhodes	if (result != ISC_R_SUCCESS) {
113135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
114135446Strhodes				 "dns_fwdtable_create() failed: %s",
115135446Strhodes				 isc_result_totext(result));
116135446Strhodes		result = ISC_R_UNEXPECTED;
117224092Sdougb		goto cleanup_zt;
118135446Strhodes	}
119135446Strhodes
120170222Sdougb	view->acache = NULL;
121135446Strhodes	view->cache = NULL;
122135446Strhodes	view->cachedb = NULL;
123170222Sdougb	view->dlzdatabase = NULL;
124135446Strhodes	view->hints = NULL;
125135446Strhodes	view->resolver = NULL;
126135446Strhodes	view->adb = NULL;
127135446Strhodes	view->requestmgr = NULL;
128135446Strhodes	view->mctx = mctx;
129135446Strhodes	view->rdclass = rdclass;
130135446Strhodes	view->frozen = ISC_FALSE;
131135446Strhodes	view->task = NULL;
132170222Sdougb	result = isc_refcount_init(&view->references, 1);
133170222Sdougb	if (result != ISC_R_SUCCESS)
134170222Sdougb		goto cleanup_fwdtable;
135135446Strhodes	view->weakrefs = 0;
136135446Strhodes	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
137135446Strhodes			    DNS_VIEWATTR_REQSHUTDOWN);
138135446Strhodes	view->statickeys = NULL;
139135446Strhodes	view->dynamickeys = NULL;
140135446Strhodes	view->matchclients = NULL;
141135446Strhodes	view->matchdestinations = NULL;
142135446Strhodes	view->matchrecursiveonly = ISC_FALSE;
143135446Strhodes	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
144135446Strhodes	if (result != ISC_R_SUCCESS)
145170222Sdougb		goto cleanup_references;
146135446Strhodes	view->peers = NULL;
147135446Strhodes	view->order = NULL;
148135446Strhodes	view->delonly = NULL;
149135446Strhodes	view->rootdelonly = ISC_FALSE;
150135446Strhodes	view->rootexclude = NULL;
151193149Sdougb	view->resstats = NULL;
152193149Sdougb	view->resquerystats = NULL;
153224092Sdougb	view->cacheshared = ISC_FALSE;
154224092Sdougb	ISC_LIST_INIT(view->dns64);
155224092Sdougb	view->dns64cnt = 0;
156135446Strhodes
157135446Strhodes	/*
158135446Strhodes	 * Initialize configuration data with default values.
159135446Strhodes	 */
160135446Strhodes	view->recursion = ISC_TRUE;
161135446Strhodes	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
162135446Strhodes	view->additionalfromcache = ISC_TRUE;
163135446Strhodes	view->additionalfromauth = ISC_TRUE;
164135446Strhodes	view->enablednssec = ISC_TRUE;
165170222Sdougb	view->enablevalidation = ISC_TRUE;
166170222Sdougb	view->acceptexpired = ISC_FALSE;
167135446Strhodes	view->minimalresponses = ISC_FALSE;
168135446Strhodes	view->transfer_format = dns_one_answer;
169216175Sdougb	view->cacheacl = NULL;
170216175Sdougb	view->cacheonacl = NULL;
171135446Strhodes	view->queryacl = NULL;
172193149Sdougb	view->queryonacl = NULL;
173135446Strhodes	view->recursionacl = NULL;
174193149Sdougb	view->recursiononacl = NULL;
175135446Strhodes	view->sortlist = NULL;
176193149Sdougb	view->transferacl = NULL;
177193149Sdougb	view->notifyacl = NULL;
178193149Sdougb	view->updateacl = NULL;
179193149Sdougb	view->upfwdacl = NULL;
180224092Sdougb	view->denyansweracl = NULL;
181224092Sdougb	view->answeracl_exclude = NULL;
182224092Sdougb	view->denyanswernames = NULL;
183224092Sdougb	view->answernames_exclude = NULL;
184135446Strhodes	view->requestixfr = ISC_TRUE;
185135446Strhodes	view->provideixfr = ISC_TRUE;
186135446Strhodes	view->maxcachettl = 7 * 24 * 3600;
187135446Strhodes	view->maxncachettl = 3 * 3600;
188135446Strhodes	view->dstport = 53;
189135446Strhodes	view->preferred_glue = 0;
190135446Strhodes	view->flush = ISC_FALSE;
191135446Strhodes	view->dlv = NULL;
192170222Sdougb	view->maxudp = 0;
193224092Sdougb	view->v4_aaaa = dns_v4_aaaa_ok;
194224092Sdougb	view->v4_aaaa_acl = NULL;
195224092Sdougb	ISC_LIST_INIT(view->rpz_zones);
196135446Strhodes	dns_fixedname_init(&view->dlv_fixed);
197224092Sdougb	view->managed_keys = NULL;
198224092Sdougb#ifdef BIND9
199224092Sdougb	view->new_zone_file = NULL;
200224092Sdougb	view->new_zone_config = NULL;
201224092Sdougb	view->cfg_destroy = NULL;
202135446Strhodes
203135446Strhodes	result = dns_order_create(view->mctx, &view->order);
204135446Strhodes	if (result != ISC_R_SUCCESS)
205135446Strhodes		goto cleanup_dynkeys;
206224092Sdougb#endif
207135446Strhodes
208135446Strhodes	result = dns_peerlist_new(view->mctx, &view->peers);
209135446Strhodes	if (result != ISC_R_SUCCESS)
210135446Strhodes		goto cleanup_order;
211135446Strhodes
212135446Strhodes	result = dns_aclenv_init(view->mctx, &view->aclenv);
213135446Strhodes	if (result != ISC_R_SUCCESS)
214135446Strhodes		goto cleanup_peerlist;
215135446Strhodes
216135446Strhodes	ISC_LINK_INIT(view, link);
217135446Strhodes	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
218135446Strhodes		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
219135446Strhodes		       view, NULL, NULL, NULL);
220135446Strhodes	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
221135446Strhodes		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
222135446Strhodes		       view, NULL, NULL, NULL);
223135446Strhodes	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
224135446Strhodes		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
225135446Strhodes		       view, NULL, NULL, NULL);
226135446Strhodes	view->magic = DNS_VIEW_MAGIC;
227135446Strhodes
228135446Strhodes	*viewp = view;
229135446Strhodes
230135446Strhodes	return (ISC_R_SUCCESS);
231135446Strhodes
232135446Strhodes cleanup_peerlist:
233135446Strhodes	dns_peerlist_detach(&view->peers);
234135446Strhodes
235135446Strhodes cleanup_order:
236224092Sdougb#ifdef BIND9
237135446Strhodes	dns_order_detach(&view->order);
238135446Strhodes
239135446Strhodes cleanup_dynkeys:
240224092Sdougb#endif
241224092Sdougb	dns_tsigkeyring_detach(&view->dynamickeys);
242135446Strhodes
243170222Sdougb cleanup_references:
244170222Sdougb	isc_refcount_destroy(&view->references);
245170222Sdougb
246135446Strhodes cleanup_fwdtable:
247135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
248135446Strhodes
249135446Strhodes cleanup_zt:
250224092Sdougb#ifdef BIND9
251135446Strhodes	dns_zt_detach(&view->zonetable);
252135446Strhodes
253135446Strhodes cleanup_mutex:
254224092Sdougb#endif
255135446Strhodes	DESTROYLOCK(&view->lock);
256135446Strhodes
257135446Strhodes cleanup_name:
258135446Strhodes	isc_mem_free(mctx, view->name);
259135446Strhodes
260135446Strhodes cleanup_view:
261135446Strhodes	isc_mem_put(mctx, view, sizeof(*view));
262135446Strhodes
263135446Strhodes	return (result);
264135446Strhodes}
265135446Strhodes
266135446Strhodesstatic inline void
267135446Strhodesdestroy(dns_view_t *view) {
268224092Sdougb#ifdef BIND9
269224092Sdougb	dns_dns64_t *dns64;
270224092Sdougb#endif
271224092Sdougb
272135446Strhodes	REQUIRE(!ISC_LINK_LINKED(view, link));
273135446Strhodes	REQUIRE(isc_refcount_current(&view->references) == 0);
274135446Strhodes	REQUIRE(view->weakrefs == 0);
275135446Strhodes	REQUIRE(RESSHUTDOWN(view));
276135446Strhodes	REQUIRE(ADBSHUTDOWN(view));
277135446Strhodes	REQUIRE(REQSHUTDOWN(view));
278135446Strhodes
279224092Sdougb#ifdef BIND9
280135446Strhodes	if (view->order != NULL)
281135446Strhodes		dns_order_detach(&view->order);
282224092Sdougb#endif
283135446Strhodes	if (view->peers != NULL)
284135446Strhodes		dns_peerlist_detach(&view->peers);
285224092Sdougb
286224092Sdougb	if (view->dynamickeys != NULL) {
287224092Sdougb		isc_result_t result;
288224092Sdougb		char template[20];
289224092Sdougb		char keyfile[20];
290224092Sdougb		FILE *fp = NULL;
291224092Sdougb		int n;
292224092Sdougb
293224092Sdougb		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
294224092Sdougb			     view->name);
295224092Sdougb		if (n > 0 && (size_t)n < sizeof(keyfile)) {
296224092Sdougb			result = isc_file_mktemplate(keyfile, template,
297224092Sdougb						     sizeof(template));
298224092Sdougb			if (result == ISC_R_SUCCESS)
299224092Sdougb				(void)isc_file_openuniqueprivate(template, &fp);
300224092Sdougb		}
301224092Sdougb		if (fp == NULL)
302224092Sdougb			dns_tsigkeyring_detach(&view->dynamickeys);
303224092Sdougb		else {
304224092Sdougb			result = dns_tsigkeyring_dumpanddetach(
305224092Sdougb							&view->dynamickeys, fp);
306224092Sdougb			if (result == ISC_R_SUCCESS) {
307224092Sdougb				if (fclose(fp) == 0)
308224092Sdougb					result = isc_file_rename(template,
309224092Sdougb								 keyfile);
310224092Sdougb				if (result != ISC_R_SUCCESS)
311224092Sdougb					(void)remove(template);
312224092Sdougb			} else {
313224092Sdougb				(void)fclose(fp);
314224092Sdougb				(void)remove(template);
315224092Sdougb			}
316224092Sdougb		}
317224092Sdougb	}
318135446Strhodes	if (view->statickeys != NULL)
319224092Sdougb		dns_tsigkeyring_detach(&view->statickeys);
320135446Strhodes	if (view->adb != NULL)
321135446Strhodes		dns_adb_detach(&view->adb);
322135446Strhodes	if (view->resolver != NULL)
323135446Strhodes		dns_resolver_detach(&view->resolver);
324224092Sdougb#ifdef BIND9
325170222Sdougb	if (view->acache != NULL) {
326170222Sdougb		if (view->cachedb != NULL)
327170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
328170222Sdougb		dns_acache_detach(&view->acache);
329170222Sdougb	}
330224092Sdougb	dns_rpz_view_destroy(view);
331224092Sdougb#else
332224092Sdougb	INSIST(view->acache == NULL);
333224092Sdougb	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
334224092Sdougb#endif
335135446Strhodes	if (view->requestmgr != NULL)
336135446Strhodes		dns_requestmgr_detach(&view->requestmgr);
337135446Strhodes	if (view->task != NULL)
338135446Strhodes		isc_task_detach(&view->task);
339135446Strhodes	if (view->hints != NULL)
340135446Strhodes		dns_db_detach(&view->hints);
341170222Sdougb	if (view->dlzdatabase != NULL)
342170222Sdougb		dns_dlzdestroy(&view->dlzdatabase);
343135446Strhodes	if (view->cachedb != NULL)
344135446Strhodes		dns_db_detach(&view->cachedb);
345135446Strhodes	if (view->cache != NULL)
346135446Strhodes		dns_cache_detach(&view->cache);
347135446Strhodes	if (view->matchclients != NULL)
348135446Strhodes		dns_acl_detach(&view->matchclients);
349135446Strhodes	if (view->matchdestinations != NULL)
350135446Strhodes		dns_acl_detach(&view->matchdestinations);
351216175Sdougb	if (view->cacheacl != NULL)
352216175Sdougb		dns_acl_detach(&view->cacheacl);
353216175Sdougb	if (view->cacheonacl != NULL)
354216175Sdougb		dns_acl_detach(&view->cacheonacl);
355135446Strhodes	if (view->queryacl != NULL)
356135446Strhodes		dns_acl_detach(&view->queryacl);
357193149Sdougb	if (view->queryonacl != NULL)
358193149Sdougb		dns_acl_detach(&view->queryonacl);
359135446Strhodes	if (view->recursionacl != NULL)
360135446Strhodes		dns_acl_detach(&view->recursionacl);
361193149Sdougb	if (view->recursiononacl != NULL)
362193149Sdougb		dns_acl_detach(&view->recursiononacl);
363135446Strhodes	if (view->sortlist != NULL)
364135446Strhodes		dns_acl_detach(&view->sortlist);
365193149Sdougb	if (view->transferacl != NULL)
366193149Sdougb		dns_acl_detach(&view->transferacl);
367193149Sdougb	if (view->notifyacl != NULL)
368193149Sdougb		dns_acl_detach(&view->notifyacl);
369193149Sdougb	if (view->updateacl != NULL)
370193149Sdougb		dns_acl_detach(&view->updateacl);
371193149Sdougb	if (view->upfwdacl != NULL)
372193149Sdougb		dns_acl_detach(&view->upfwdacl);
373224092Sdougb	if (view->denyansweracl != NULL)
374224092Sdougb		dns_acl_detach(&view->denyansweracl);
375224092Sdougb	if (view->v4_aaaa_acl != NULL)
376224092Sdougb		dns_acl_detach(&view->v4_aaaa_acl);
377224092Sdougb	if (view->answeracl_exclude != NULL)
378224092Sdougb		dns_rbt_destroy(&view->answeracl_exclude);
379224092Sdougb	if (view->denyanswernames != NULL)
380224092Sdougb		dns_rbt_destroy(&view->denyanswernames);
381224092Sdougb	if (view->answernames_exclude != NULL)
382224092Sdougb		dns_rbt_destroy(&view->answernames_exclude);
383135446Strhodes	if (view->delonly != NULL) {
384135446Strhodes		dns_name_t *name;
385135446Strhodes		int i;
386135446Strhodes
387135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
388135446Strhodes			name = ISC_LIST_HEAD(view->delonly[i]);
389135446Strhodes			while (name != NULL) {
390135446Strhodes				ISC_LIST_UNLINK(view->delonly[i], name, link);
391135446Strhodes				dns_name_free(name, view->mctx);
392135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
393135446Strhodes				name = ISC_LIST_HEAD(view->delonly[i]);
394135446Strhodes			}
395135446Strhodes		}
396135446Strhodes		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
397135446Strhodes			    DNS_VIEW_DELONLYHASH);
398135446Strhodes		view->delonly = NULL;
399135446Strhodes	}
400135446Strhodes	if (view->rootexclude != NULL) {
401135446Strhodes		dns_name_t *name;
402135446Strhodes		int i;
403135446Strhodes
404135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
405135446Strhodes			name = ISC_LIST_HEAD(view->rootexclude[i]);
406135446Strhodes			while (name != NULL) {
407135446Strhodes				ISC_LIST_UNLINK(view->rootexclude[i],
408186462Sdougb						name, link);
409135446Strhodes				dns_name_free(name, view->mctx);
410135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
411135446Strhodes				name = ISC_LIST_HEAD(view->rootexclude[i]);
412135446Strhodes			}
413135446Strhodes		}
414135446Strhodes		isc_mem_put(view->mctx, view->rootexclude,
415135446Strhodes			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
416135446Strhodes		view->rootexclude = NULL;
417135446Strhodes	}
418193149Sdougb	if (view->resstats != NULL)
419193149Sdougb		isc_stats_detach(&view->resstats);
420193149Sdougb	if (view->resquerystats != NULL)
421193149Sdougb		dns_stats_detach(&view->resquerystats);
422224092Sdougb	if (view->secroots_priv != NULL)
423224092Sdougb		dns_keytable_detach(&view->secroots_priv);
424224092Sdougb#ifdef BIND9
425224092Sdougb	for (dns64 = ISC_LIST_HEAD(view->dns64);
426224092Sdougb	     dns64 != NULL;
427224092Sdougb	     dns64 = ISC_LIST_HEAD(view->dns64)) {
428224092Sdougb		dns_dns64_unlink(&view->dns64, dns64);
429224092Sdougb		dns_dns64_destroy(&dns64);
430224092Sdougb	}
431224092Sdougb	if (view->managed_keys != NULL)
432224092Sdougb		dns_zone_detach(&view->managed_keys);
433224092Sdougb	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
434224092Sdougb#endif
435135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
436135446Strhodes	dns_aclenv_destroy(&view->aclenv);
437135446Strhodes	DESTROYLOCK(&view->lock);
438135446Strhodes	isc_refcount_destroy(&view->references);
439135446Strhodes	isc_mem_free(view->mctx, view->name);
440135446Strhodes	isc_mem_put(view->mctx, view, sizeof(*view));
441135446Strhodes}
442135446Strhodes
443135446Strhodes/*
444135446Strhodes * Return true iff 'view' may be freed.
445135446Strhodes * The caller must be holding the view lock.
446135446Strhodes */
447135446Strhodesstatic isc_boolean_t
448135446Strhodesall_done(dns_view_t *view) {
449135446Strhodes
450135446Strhodes	if (isc_refcount_current(&view->references) == 0 &&
451135446Strhodes	    view->weakrefs == 0 &&
452135446Strhodes	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
453135446Strhodes		return (ISC_TRUE);
454135446Strhodes
455135446Strhodes	return (ISC_FALSE);
456135446Strhodes}
457135446Strhodes
458135446Strhodesvoid
459135446Strhodesdns_view_attach(dns_view_t *source, dns_view_t **targetp) {
460135446Strhodes
461135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
462135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
463135446Strhodes
464135446Strhodes	isc_refcount_increment(&source->references, NULL);
465135446Strhodes
466135446Strhodes	*targetp = source;
467135446Strhodes}
468135446Strhodes
469135446Strhodesstatic void
470135446Strhodesview_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
471135446Strhodes	dns_view_t *view;
472135446Strhodes	unsigned int refs;
473135446Strhodes	isc_boolean_t done = ISC_FALSE;
474135446Strhodes
475135446Strhodes	REQUIRE(viewp != NULL);
476135446Strhodes	view = *viewp;
477135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
478135446Strhodes
479135446Strhodes	if (flush)
480135446Strhodes		view->flush = ISC_TRUE;
481135446Strhodes	isc_refcount_decrement(&view->references, &refs);
482135446Strhodes	if (refs == 0) {
483135446Strhodes		LOCK(&view->lock);
484135446Strhodes		if (!RESSHUTDOWN(view))
485135446Strhodes			dns_resolver_shutdown(view->resolver);
486135446Strhodes		if (!ADBSHUTDOWN(view))
487135446Strhodes			dns_adb_shutdown(view->adb);
488135446Strhodes		if (!REQSHUTDOWN(view))
489135446Strhodes			dns_requestmgr_shutdown(view->requestmgr);
490224092Sdougb#ifdef BIND9
491170222Sdougb		if (view->acache != NULL)
492170222Sdougb			dns_acache_shutdown(view->acache);
493135446Strhodes		if (view->flush)
494135446Strhodes			dns_zt_flushanddetach(&view->zonetable);
495135446Strhodes		else
496135446Strhodes			dns_zt_detach(&view->zonetable);
497224092Sdougb		if (view->managed_keys != NULL) {
498224092Sdougb			if (view->flush)
499224092Sdougb				dns_zone_flush(view->managed_keys);
500224092Sdougb			dns_zone_detach(&view->managed_keys);
501224092Sdougb		}
502224092Sdougb#endif
503135446Strhodes		done = all_done(view);
504135446Strhodes		UNLOCK(&view->lock);
505135446Strhodes	}
506135446Strhodes
507135446Strhodes	*viewp = NULL;
508135446Strhodes
509135446Strhodes	if (done)
510135446Strhodes		destroy(view);
511135446Strhodes}
512135446Strhodes
513135446Strhodesvoid
514135446Strhodesdns_view_flushanddetach(dns_view_t **viewp) {
515135446Strhodes	view_flushanddetach(viewp, ISC_TRUE);
516135446Strhodes}
517135446Strhodes
518135446Strhodesvoid
519135446Strhodesdns_view_detach(dns_view_t **viewp) {
520135446Strhodes	view_flushanddetach(viewp, ISC_FALSE);
521135446Strhodes}
522135446Strhodes
523224092Sdougb#ifdef BIND9
524135446Strhodesstatic isc_result_t
525135446Strhodesdialup(dns_zone_t *zone, void *dummy) {
526135446Strhodes	UNUSED(dummy);
527135446Strhodes	dns_zone_dialup(zone);
528135446Strhodes	return (ISC_R_SUCCESS);
529135446Strhodes}
530135446Strhodes
531135446Strhodesvoid
532135446Strhodesdns_view_dialup(dns_view_t *view) {
533135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
534135446Strhodes	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
535135446Strhodes}
536224092Sdougb#endif
537135446Strhodes
538135446Strhodesvoid
539135446Strhodesdns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
540135446Strhodes
541135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
542135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
543135446Strhodes
544135446Strhodes	LOCK(&source->lock);
545135446Strhodes	source->weakrefs++;
546135446Strhodes	UNLOCK(&source->lock);
547135446Strhodes
548135446Strhodes	*targetp = source;
549135446Strhodes}
550135446Strhodes
551135446Strhodesvoid
552135446Strhodesdns_view_weakdetach(dns_view_t **viewp) {
553135446Strhodes	dns_view_t *view;
554135446Strhodes	isc_boolean_t done = ISC_FALSE;
555135446Strhodes
556135446Strhodes	REQUIRE(viewp != NULL);
557135446Strhodes	view = *viewp;
558135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
559135446Strhodes
560135446Strhodes	LOCK(&view->lock);
561135446Strhodes
562135446Strhodes	INSIST(view->weakrefs > 0);
563135446Strhodes	view->weakrefs--;
564135446Strhodes	done = all_done(view);
565135446Strhodes
566135446Strhodes	UNLOCK(&view->lock);
567135446Strhodes
568135446Strhodes	*viewp = NULL;
569135446Strhodes
570135446Strhodes	if (done)
571135446Strhodes		destroy(view);
572135446Strhodes}
573135446Strhodes
574135446Strhodesstatic void
575135446Strhodesresolver_shutdown(isc_task_t *task, isc_event_t *event) {
576135446Strhodes	dns_view_t *view = event->ev_arg;
577135446Strhodes	isc_boolean_t done;
578135446Strhodes
579135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
580135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
581135446Strhodes	REQUIRE(view->task == task);
582135446Strhodes
583135446Strhodes	UNUSED(task);
584135446Strhodes
585135446Strhodes	LOCK(&view->lock);
586135446Strhodes
587135446Strhodes	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
588135446Strhodes	done = all_done(view);
589135446Strhodes
590135446Strhodes	UNLOCK(&view->lock);
591135446Strhodes
592135446Strhodes	isc_event_free(&event);
593135446Strhodes
594135446Strhodes	if (done)
595135446Strhodes		destroy(view);
596135446Strhodes}
597135446Strhodes
598135446Strhodesstatic void
599135446Strhodesadb_shutdown(isc_task_t *task, isc_event_t *event) {
600135446Strhodes	dns_view_t *view = event->ev_arg;
601135446Strhodes	isc_boolean_t done;
602135446Strhodes
603135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
604135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
605135446Strhodes	REQUIRE(view->task == task);
606135446Strhodes
607135446Strhodes	UNUSED(task);
608135446Strhodes
609135446Strhodes	LOCK(&view->lock);
610135446Strhodes
611135446Strhodes	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
612135446Strhodes	done = all_done(view);
613135446Strhodes
614135446Strhodes	UNLOCK(&view->lock);
615135446Strhodes
616135446Strhodes	isc_event_free(&event);
617135446Strhodes
618135446Strhodes	if (done)
619135446Strhodes		destroy(view);
620135446Strhodes}
621135446Strhodes
622135446Strhodesstatic void
623135446Strhodesreq_shutdown(isc_task_t *task, isc_event_t *event) {
624135446Strhodes	dns_view_t *view = event->ev_arg;
625135446Strhodes	isc_boolean_t done;
626135446Strhodes
627135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
628135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
629135446Strhodes	REQUIRE(view->task == task);
630135446Strhodes
631135446Strhodes	UNUSED(task);
632135446Strhodes
633135446Strhodes	LOCK(&view->lock);
634135446Strhodes
635135446Strhodes	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
636135446Strhodes	done = all_done(view);
637135446Strhodes
638135446Strhodes	UNLOCK(&view->lock);
639135446Strhodes
640135446Strhodes	isc_event_free(&event);
641135446Strhodes
642135446Strhodes	if (done)
643135446Strhodes		destroy(view);
644135446Strhodes}
645135446Strhodes
646135446Strhodesisc_result_t
647135446Strhodesdns_view_createresolver(dns_view_t *view,
648135446Strhodes			isc_taskmgr_t *taskmgr, unsigned int ntasks,
649135446Strhodes			isc_socketmgr_t *socketmgr,
650135446Strhodes			isc_timermgr_t *timermgr,
651135446Strhodes			unsigned int options,
652135446Strhodes			dns_dispatchmgr_t *dispatchmgr,
653135446Strhodes			dns_dispatch_t *dispatchv4,
654135446Strhodes			dns_dispatch_t *dispatchv6)
655135446Strhodes{
656135446Strhodes	isc_result_t result;
657135446Strhodes	isc_event_t *event;
658135446Strhodes	isc_mem_t *mctx = NULL;
659135446Strhodes
660135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
661135446Strhodes	REQUIRE(!view->frozen);
662135446Strhodes	REQUIRE(view->resolver == NULL);
663135446Strhodes
664135446Strhodes	result = isc_task_create(taskmgr, 0, &view->task);
665135446Strhodes	if (result != ISC_R_SUCCESS)
666135446Strhodes		return (result);
667135446Strhodes	isc_task_setname(view->task, "view", view);
668135446Strhodes
669135446Strhodes	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
670135446Strhodes				     timermgr, options, dispatchmgr,
671135446Strhodes				     dispatchv4, dispatchv6,
672135446Strhodes				     &view->resolver);
673135446Strhodes	if (result != ISC_R_SUCCESS) {
674135446Strhodes		isc_task_detach(&view->task);
675135446Strhodes		return (result);
676135446Strhodes	}
677135446Strhodes	event = &view->resevent;
678135446Strhodes	dns_resolver_whenshutdown(view->resolver, view->task, &event);
679135446Strhodes	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
680135446Strhodes
681135446Strhodes	result = isc_mem_create(0, 0, &mctx);
682135446Strhodes	if (result != ISC_R_SUCCESS) {
683135446Strhodes		dns_resolver_shutdown(view->resolver);
684135446Strhodes		return (result);
685135446Strhodes	}
686135446Strhodes
687135446Strhodes	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
688193149Sdougb	isc_mem_setname(mctx, "ADB", NULL);
689135446Strhodes	isc_mem_detach(&mctx);
690135446Strhodes	if (result != ISC_R_SUCCESS) {
691135446Strhodes		dns_resolver_shutdown(view->resolver);
692135446Strhodes		return (result);
693135446Strhodes	}
694135446Strhodes	event = &view->adbevent;
695135446Strhodes	dns_adb_whenshutdown(view->adb, view->task, &event);
696135446Strhodes	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
697135446Strhodes
698135446Strhodes	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
699135446Strhodes				      dns_resolver_taskmgr(view->resolver),
700135446Strhodes				      dns_resolver_dispatchmgr(view->resolver),
701135446Strhodes				      dns_resolver_dispatchv4(view->resolver),
702135446Strhodes				      dns_resolver_dispatchv6(view->resolver),
703135446Strhodes				      &view->requestmgr);
704135446Strhodes	if (result != ISC_R_SUCCESS) {
705135446Strhodes		dns_adb_shutdown(view->adb);
706135446Strhodes		dns_resolver_shutdown(view->resolver);
707135446Strhodes		return (result);
708135446Strhodes	}
709135446Strhodes	event = &view->reqevent;
710135446Strhodes	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
711135446Strhodes	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
712135446Strhodes
713135446Strhodes	return (ISC_R_SUCCESS);
714135446Strhodes}
715135446Strhodes
716135446Strhodesvoid
717135446Strhodesdns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
718224092Sdougb	dns_view_setcache2(view, cache, ISC_FALSE);
719224092Sdougb}
720224092Sdougb
721224092Sdougbvoid
722224092Sdougbdns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
723135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
724135446Strhodes	REQUIRE(!view->frozen);
725135446Strhodes
726224092Sdougb	view->cacheshared = shared;
727135446Strhodes	if (view->cache != NULL) {
728224092Sdougb#ifdef BIND9
729170222Sdougb		if (view->acache != NULL)
730170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
731224092Sdougb#endif
732135446Strhodes		dns_db_detach(&view->cachedb);
733135446Strhodes		dns_cache_detach(&view->cache);
734135446Strhodes	}
735135446Strhodes	dns_cache_attach(cache, &view->cache);
736135446Strhodes	dns_cache_attachdb(cache, &view->cachedb);
737135446Strhodes	INSIST(DNS_DB_VALID(view->cachedb));
738170222Sdougb
739224092Sdougb#ifdef BIND9
740170222Sdougb	if (view->acache != NULL)
741170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
742224092Sdougb#endif
743135446Strhodes}
744135446Strhodes
745224092Sdougbisc_boolean_t
746224092Sdougbdns_view_iscacheshared(dns_view_t *view) {
747224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
748224092Sdougb
749224092Sdougb	return (view->cacheshared);
750224092Sdougb}
751224092Sdougb
752135446Strhodesvoid
753135446Strhodesdns_view_sethints(dns_view_t *view, dns_db_t *hints) {
754135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
755135446Strhodes	REQUIRE(!view->frozen);
756135446Strhodes	REQUIRE(view->hints == NULL);
757135446Strhodes	REQUIRE(dns_db_iszone(hints));
758135446Strhodes
759135446Strhodes	dns_db_attach(hints, &view->hints);
760135446Strhodes}
761135446Strhodes
762135446Strhodesvoid
763135446Strhodesdns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
764135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
765135446Strhodes	REQUIRE(ring != NULL);
766135446Strhodes	if (view->statickeys != NULL)
767224092Sdougb		dns_tsigkeyring_detach(&view->statickeys);
768224092Sdougb	dns_tsigkeyring_attach(ring, &view->statickeys);
769135446Strhodes}
770135446Strhodes
771135446Strhodesvoid
772224092Sdougbdns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
773135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
774224092Sdougb	REQUIRE(ring != NULL);
775224092Sdougb	if (view->dynamickeys != NULL)
776224092Sdougb		dns_tsigkeyring_detach(&view->dynamickeys);
777224092Sdougb	dns_tsigkeyring_attach(ring, &view->dynamickeys);
778135446Strhodes}
779135446Strhodes
780224092Sdougbvoid
781224092Sdougbdns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
782224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
783224092Sdougb	REQUIRE(ringp != NULL && *ringp == NULL);
784224092Sdougb	if (view->dynamickeys != NULL)
785224092Sdougb		dns_tsigkeyring_attach(view->dynamickeys, ringp);
786224092Sdougb}
787135446Strhodes
788224092Sdougbvoid
789224092Sdougbdns_view_restorekeyring(dns_view_t *view) {
790224092Sdougb	FILE *fp;
791224092Sdougb	char keyfile[20];
792224092Sdougb	int n;
793224092Sdougb
794135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
795135446Strhodes
796224092Sdougb	if (view->dynamickeys != NULL) {
797224092Sdougb		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
798224092Sdougb			     view->name);
799224092Sdougb		if (n > 0 && (size_t)n < sizeof(keyfile)) {
800224092Sdougb			fp = fopen(keyfile, "r");
801224092Sdougb			if (fp != NULL) {
802224092Sdougb				dns_keyring_restore(view->dynamickeys, fp);
803224092Sdougb				(void)fclose(fp);
804224092Sdougb			}
805224092Sdougb		}
806224092Sdougb	}
807224092Sdougb}
808135446Strhodes
809224092Sdougbvoid
810224092Sdougbdns_view_setdstport(dns_view_t *view, in_port_t dstport) {
811224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
812224092Sdougb	view->dstport = dstport;
813135446Strhodes}
814135446Strhodes
815135446Strhodesvoid
816135446Strhodesdns_view_freeze(dns_view_t *view) {
817135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
818135446Strhodes	REQUIRE(!view->frozen);
819135446Strhodes
820135446Strhodes	if (view->resolver != NULL) {
821135446Strhodes		INSIST(view->cachedb != NULL);
822135446Strhodes		dns_resolver_freeze(view->resolver);
823135446Strhodes	}
824135446Strhodes	view->frozen = ISC_TRUE;
825135446Strhodes}
826135446Strhodes
827224092Sdougb#ifdef BIND9
828224092Sdougbvoid
829224092Sdougbdns_view_thaw(dns_view_t *view) {
830224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
831224092Sdougb	REQUIRE(view->frozen);
832224092Sdougb
833224092Sdougb	view->frozen = ISC_FALSE;
834224092Sdougb}
835224092Sdougb
836135446Strhodesisc_result_t
837224092Sdougbdns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
838224092Sdougb	isc_result_t result;
839224092Sdougb
840224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
841224092Sdougb	REQUIRE(!view->frozen);
842224092Sdougb
843224092Sdougb	result = dns_zt_mount(view->zonetable, zone);
844224092Sdougb
845224092Sdougb	return (result);
846224092Sdougb}
847224092Sdougb#endif
848224092Sdougb
849224092Sdougb#ifdef BIND9
850224092Sdougbisc_result_t
851135446Strhodesdns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
852135446Strhodes	isc_result_t result;
853135446Strhodes
854135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
855135446Strhodes
856135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
857135446Strhodes	if (result == DNS_R_PARTIALMATCH) {
858135446Strhodes		dns_zone_detach(zonep);
859135446Strhodes		result = ISC_R_NOTFOUND;
860135446Strhodes	}
861135446Strhodes
862135446Strhodes	return (result);
863135446Strhodes}
864224092Sdougb#endif
865135446Strhodes
866135446Strhodesisc_result_t
867135446Strhodesdns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
868135446Strhodes	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
869135446Strhodes	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
870224092Sdougb	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
871224092Sdougb	return (dns_view_find2(view, name, type, now, options, use_hints,
872224092Sdougb			       ISC_FALSE, dbp, nodep, foundname, rdataset,
873224092Sdougb			       sigrdataset));
874224092Sdougb}
875224092Sdougb
876224092Sdougbisc_result_t
877224092Sdougbdns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
878224092Sdougb	       isc_stdtime_t now, unsigned int options,
879224092Sdougb	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
880224092Sdougb	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
881224092Sdougb	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
882135446Strhodes{
883135446Strhodes	isc_result_t result;
884135446Strhodes	dns_db_t *db, *zdb;
885135446Strhodes	dns_dbnode_t *node, *znode;
886224092Sdougb	isc_boolean_t is_cache, is_staticstub_zone;
887135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
888135446Strhodes	dns_zone_t *zone;
889135446Strhodes
890224092Sdougb#ifndef BIND9
891224092Sdougb	UNUSED(use_hints);
892224092Sdougb	UNUSED(use_static_stub);
893224092Sdougb#endif
894224092Sdougb
895135446Strhodes	/*
896135446Strhodes	 * Find an rdataset whose owner name is 'name', and whose type is
897135446Strhodes	 * 'type'.
898135446Strhodes	 */
899135446Strhodes
900135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
901135446Strhodes	REQUIRE(view->frozen);
902135446Strhodes	REQUIRE(type != dns_rdatatype_rrsig);
903135446Strhodes	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
904174187Sdougb	REQUIRE(nodep == NULL || *nodep == NULL);
905135446Strhodes
906135446Strhodes	/*
907135446Strhodes	 * Initialize.
908135446Strhodes	 */
909135446Strhodes	dns_rdataset_init(&zrdataset);
910135446Strhodes	dns_rdataset_init(&zsigrdataset);
911135446Strhodes	zdb = NULL;
912135446Strhodes	znode = NULL;
913135446Strhodes
914135446Strhodes	/*
915135446Strhodes	 * Find a database to answer the query.
916135446Strhodes	 */
917135446Strhodes	zone = NULL;
918135446Strhodes	db = NULL;
919135446Strhodes	node = NULL;
920224092Sdougb	is_staticstub_zone = ISC_FALSE;
921224092Sdougb#ifdef BIND9
922135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
923224092Sdougb	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
924224092Sdougb	    !use_static_stub) {
925224092Sdougb		result = ISC_R_NOTFOUND;
926224092Sdougb	}
927135446Strhodes	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
928135446Strhodes		result = dns_zone_getdb(zone, &db);
929135446Strhodes		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
930135446Strhodes			dns_db_attach(view->cachedb, &db);
931135446Strhodes		else if (result != ISC_R_SUCCESS)
932135446Strhodes			goto cleanup;
933224092Sdougb		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
934224092Sdougb		    dns_name_equal(name, dns_zone_getorigin(zone))) {
935224092Sdougb			is_staticstub_zone = ISC_TRUE;
936224092Sdougb		}
937135446Strhodes	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
938135446Strhodes		dns_db_attach(view->cachedb, &db);
939224092Sdougb#else
940224092Sdougb	result = ISC_R_NOTFOUND;
941224092Sdougb	if (view->cachedb != NULL)
942224092Sdougb		dns_db_attach(view->cachedb, &db);
943224092Sdougb#endif /* BIND9 */
944135446Strhodes	else
945135446Strhodes		goto cleanup;
946135446Strhodes
947135446Strhodes	is_cache = dns_db_iscache(db);
948135446Strhodes
949135446Strhodes db_find:
950135446Strhodes	/*
951135446Strhodes	 * Now look for an answer in the database.
952135446Strhodes	 */
953135446Strhodes	result = dns_db_find(db, name, NULL, type, options,
954135446Strhodes			     now, &node, foundname, rdataset, sigrdataset);
955135446Strhodes
956224092Sdougb	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
957135446Strhodes		if (dns_rdataset_isassociated(rdataset))
958135446Strhodes			dns_rdataset_disassociate(rdataset);
959135446Strhodes		if (sigrdataset != NULL &&
960135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
961135446Strhodes			dns_rdataset_disassociate(sigrdataset);
962135446Strhodes		if (node != NULL)
963135446Strhodes			dns_db_detachnode(db, &node);
964135446Strhodes		if (!is_cache) {
965135446Strhodes			dns_db_detach(&db);
966224092Sdougb			if (view->cachedb != NULL && !is_staticstub_zone) {
967135446Strhodes				/*
968135446Strhodes				 * Either the answer is in the cache, or we
969135446Strhodes				 * don't know it.
970224092Sdougb				 * Note that if the result comes from a
971224092Sdougb				 * static-stub zone we stop the search here
972224092Sdougb				 * (see the function description in view.h).
973135446Strhodes				 */
974135446Strhodes				is_cache = ISC_TRUE;
975135446Strhodes				dns_db_attach(view->cachedb, &db);
976135446Strhodes				goto db_find;
977135446Strhodes			}
978135446Strhodes		} else {
979135446Strhodes			/*
980135446Strhodes			 * We don't have the data in the cache.  If we've got
981135446Strhodes			 * glue from the zone, use it.
982135446Strhodes			 */
983135446Strhodes			if (dns_rdataset_isassociated(&zrdataset)) {
984135446Strhodes				dns_rdataset_clone(&zrdataset, rdataset);
985135446Strhodes				if (sigrdataset != NULL &&
986135446Strhodes				    dns_rdataset_isassociated(&zsigrdataset))
987135446Strhodes					dns_rdataset_clone(&zsigrdataset,
988135446Strhodes							   sigrdataset);
989135446Strhodes				result = DNS_R_GLUE;
990135446Strhodes				if (db != NULL)
991135446Strhodes					dns_db_detach(&db);
992135446Strhodes				dns_db_attach(zdb, &db);
993135446Strhodes				dns_db_attachnode(db, znode, &node);
994135446Strhodes				goto cleanup;
995135446Strhodes			}
996135446Strhodes		}
997135446Strhodes		/*
998135446Strhodes		 * We don't know the answer.
999135446Strhodes		 */
1000135446Strhodes		result = ISC_R_NOTFOUND;
1001135446Strhodes	} else if (result == DNS_R_GLUE) {
1002224092Sdougb		if (view->cachedb != NULL && !is_staticstub_zone) {
1003135446Strhodes			/*
1004135446Strhodes			 * We found an answer, but the cache may be better.
1005135446Strhodes			 * Remember what we've got and go look in the cache.
1006135446Strhodes			 */
1007135446Strhodes			is_cache = ISC_TRUE;
1008135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
1009135446Strhodes			dns_rdataset_disassociate(rdataset);
1010135446Strhodes			if (sigrdataset != NULL &&
1011135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
1012135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1013135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1014135446Strhodes			}
1015135446Strhodes			dns_db_attach(db, &zdb);
1016135446Strhodes			dns_db_attachnode(zdb, node, &znode);
1017135446Strhodes			dns_db_detachnode(db, &node);
1018135446Strhodes			dns_db_detach(&db);
1019135446Strhodes			dns_db_attach(view->cachedb, &db);
1020135446Strhodes			goto db_find;
1021135446Strhodes		}
1022135446Strhodes		/*
1023135446Strhodes		 * Otherwise, the glue is the best answer.
1024135446Strhodes		 */
1025135446Strhodes		result = ISC_R_SUCCESS;
1026135446Strhodes	}
1027135446Strhodes
1028224092Sdougb#ifdef BIND9
1029135446Strhodes	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1030135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1031135446Strhodes			dns_rdataset_disassociate(rdataset);
1032135446Strhodes		if (sigrdataset != NULL &&
1033135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1034135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1035135446Strhodes		if (db != NULL) {
1036135446Strhodes			if (node != NULL)
1037135446Strhodes				dns_db_detachnode(db, &node);
1038135446Strhodes			dns_db_detach(&db);
1039135446Strhodes		}
1040135446Strhodes		result = dns_db_find(view->hints, name, NULL, type, options,
1041135446Strhodes				     now, &node, foundname,
1042135446Strhodes				     rdataset, sigrdataset);
1043135446Strhodes		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1044135446Strhodes			/*
1045135446Strhodes			 * We just used a hint.  Let the resolver know it
1046135446Strhodes			 * should consider priming.
1047135446Strhodes			 */
1048135446Strhodes			dns_resolver_prime(view->resolver);
1049135446Strhodes			dns_db_attach(view->hints, &db);
1050135446Strhodes			result = DNS_R_HINT;
1051135446Strhodes		} else if (result == DNS_R_NXRRSET) {
1052135446Strhodes			dns_db_attach(view->hints, &db);
1053135446Strhodes			result = DNS_R_HINTNXRRSET;
1054135446Strhodes		} else if (result == DNS_R_NXDOMAIN)
1055135446Strhodes			result = ISC_R_NOTFOUND;
1056135446Strhodes
1057135446Strhodes		/*
1058135446Strhodes		 * Cleanup if non-standard hints are used.
1059135446Strhodes		 */
1060135446Strhodes		if (db == NULL && node != NULL)
1061135446Strhodes			dns_db_detachnode(view->hints, &node);
1062135446Strhodes	}
1063224092Sdougb#endif /* BIND9 */
1064135446Strhodes
1065135446Strhodes cleanup:
1066135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
1067135446Strhodes		dns_rdataset_disassociate(&zrdataset);
1068135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
1069135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
1070135446Strhodes	}
1071135446Strhodes
1072135446Strhodes	if (zdb != NULL) {
1073135446Strhodes		if (znode != NULL)
1074135446Strhodes			dns_db_detachnode(zdb, &znode);
1075135446Strhodes		dns_db_detach(&zdb);
1076135446Strhodes	}
1077135446Strhodes
1078135446Strhodes	if (db != NULL) {
1079135446Strhodes		if (node != NULL) {
1080135446Strhodes			if (nodep != NULL)
1081135446Strhodes				*nodep = node;
1082135446Strhodes			else
1083135446Strhodes				dns_db_detachnode(db, &node);
1084135446Strhodes		}
1085135446Strhodes		if (dbp != NULL)
1086135446Strhodes			*dbp = db;
1087135446Strhodes		else
1088135446Strhodes			dns_db_detach(&db);
1089135446Strhodes	} else
1090135446Strhodes		INSIST(node == NULL);
1091135446Strhodes
1092224092Sdougb#ifdef BIND9
1093135446Strhodes	if (zone != NULL)
1094135446Strhodes		dns_zone_detach(&zone);
1095224092Sdougb#endif
1096135446Strhodes
1097135446Strhodes	return (result);
1098135446Strhodes}
1099135446Strhodes
1100135446Strhodesisc_result_t
1101135446Strhodesdns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1102135446Strhodes		    isc_stdtime_t now, unsigned int options,
1103135446Strhodes		    isc_boolean_t use_hints,
1104135446Strhodes		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1105135446Strhodes{
1106135446Strhodes	isc_result_t result;
1107135446Strhodes	dns_fixedname_t foundname;
1108135446Strhodes
1109135446Strhodes	dns_fixedname_init(&foundname);
1110135446Strhodes	result = dns_view_find(view, name, type, now, options, use_hints,
1111135446Strhodes			       NULL, NULL, dns_fixedname_name(&foundname),
1112135446Strhodes			       rdataset, sigrdataset);
1113135446Strhodes	if (result == DNS_R_NXDOMAIN) {
1114135446Strhodes		/*
1115135446Strhodes		 * The rdataset and sigrdataset of the relevant NSEC record
1116135446Strhodes		 * may be returned, but the caller cannot use them because
1117135446Strhodes		 * foundname is not returned by this simplified API.  We
1118135446Strhodes		 * disassociate them here to prevent any misuse by the caller.
1119135446Strhodes		 */
1120135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1121135446Strhodes			dns_rdataset_disassociate(rdataset);
1122135446Strhodes		if (sigrdataset != NULL &&
1123135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1124135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1125135446Strhodes	} else if (result != ISC_R_SUCCESS &&
1126135446Strhodes		   result != DNS_R_GLUE &&
1127135446Strhodes		   result != DNS_R_HINT &&
1128135446Strhodes		   result != DNS_R_NCACHENXDOMAIN &&
1129135446Strhodes		   result != DNS_R_NCACHENXRRSET &&
1130135446Strhodes		   result != DNS_R_NXRRSET &&
1131135446Strhodes		   result != DNS_R_HINTNXRRSET &&
1132135446Strhodes		   result != ISC_R_NOTFOUND) {
1133135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1134135446Strhodes			dns_rdataset_disassociate(rdataset);
1135135446Strhodes		if (sigrdataset != NULL &&
1136135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1137135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1138135446Strhodes		result = ISC_R_NOTFOUND;
1139135446Strhodes	}
1140135446Strhodes
1141135446Strhodes	return (result);
1142135446Strhodes}
1143135446Strhodes
1144135446Strhodesisc_result_t
1145135446Strhodesdns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1146135446Strhodes		     isc_stdtime_t now, unsigned int options,
1147186462Sdougb		     isc_boolean_t use_hints,
1148135446Strhodes		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1149135446Strhodes{
1150135446Strhodes	return(dns_view_findzonecut2(view, name, fname, now, options,
1151135446Strhodes				     use_hints, ISC_TRUE,
1152135446Strhodes				     rdataset, sigrdataset));
1153135446Strhodes}
1154135446Strhodes
1155135446Strhodesisc_result_t
1156135446Strhodesdns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1157135446Strhodes		      isc_stdtime_t now, unsigned int options,
1158224092Sdougb		      isc_boolean_t use_hints,	isc_boolean_t use_cache,
1159135446Strhodes		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1160135446Strhodes{
1161135446Strhodes	isc_result_t result;
1162135446Strhodes	dns_db_t *db;
1163224092Sdougb	isc_boolean_t is_cache, use_zone, try_hints, is_staticstub_zone;
1164135446Strhodes	dns_zone_t *zone;
1165135446Strhodes	dns_name_t *zfname;
1166135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
1167135446Strhodes	dns_fixedname_t zfixedname;
1168135446Strhodes
1169135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1170135446Strhodes	REQUIRE(view->frozen);
1171135446Strhodes
1172135446Strhodes	db = NULL;
1173135446Strhodes	zone = NULL;
1174135446Strhodes	use_zone = ISC_FALSE;
1175224092Sdougb	is_staticstub_zone = ISC_FALSE;
1176135446Strhodes	try_hints = ISC_FALSE;
1177135446Strhodes	zfname = NULL;
1178135446Strhodes
1179135446Strhodes	/*
1180135446Strhodes	 * Initialize.
1181135446Strhodes	 */
1182135446Strhodes	dns_fixedname_init(&zfixedname);
1183135446Strhodes	dns_rdataset_init(&zrdataset);
1184135446Strhodes	dns_rdataset_init(&zsigrdataset);
1185135446Strhodes
1186135446Strhodes	/*
1187135446Strhodes	 * Find the right database.
1188135446Strhodes	 */
1189224092Sdougb#ifdef BIND9
1190135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1191224092Sdougb	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
1192135446Strhodes		result = dns_zone_getdb(zone, &db);
1193224092Sdougb		if (dns_zone_gettype(zone) == dns_zone_staticstub)
1194224092Sdougb			is_staticstub_zone = ISC_TRUE;
1195224092Sdougb	}
1196224092Sdougb#else
1197224092Sdougb	result = ISC_R_NOTFOUND;
1198224092Sdougb#endif
1199135446Strhodes	if (result == ISC_R_NOTFOUND) {
1200135446Strhodes		/*
1201135446Strhodes		 * We're not directly authoritative for this query name, nor
1202135446Strhodes		 * is it a subdomain of any zone for which we're
1203135446Strhodes		 * authoritative.
1204135446Strhodes		 */
1205135446Strhodes		if (use_cache && view->cachedb != NULL) {
1206135446Strhodes			/*
1207135446Strhodes			 * We have a cache; try it.
1208135446Strhodes			 */
1209135446Strhodes			dns_db_attach(view->cachedb, &db);
1210135446Strhodes		} else {
1211135446Strhodes			/*
1212135446Strhodes			 * Maybe we have hints...
1213135446Strhodes			 */
1214135446Strhodes			try_hints = ISC_TRUE;
1215135446Strhodes			goto finish;
1216135446Strhodes		}
1217135446Strhodes	} else if (result != ISC_R_SUCCESS) {
1218135446Strhodes		/*
1219135446Strhodes		 * Something is broken.
1220135446Strhodes		 */
1221135446Strhodes		goto cleanup;
1222135446Strhodes	}
1223135446Strhodes	is_cache = dns_db_iscache(db);
1224135446Strhodes
1225135446Strhodes db_find:
1226135446Strhodes	/*
1227135446Strhodes	 * Look for the zonecut.
1228135446Strhodes	 */
1229135446Strhodes	if (!is_cache) {
1230135446Strhodes		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1231135446Strhodes				     now, NULL, fname, rdataset, sigrdataset);
1232135446Strhodes		if (result == DNS_R_DELEGATION)
1233135446Strhodes			result = ISC_R_SUCCESS;
1234135446Strhodes		else if (result != ISC_R_SUCCESS)
1235135446Strhodes			goto cleanup;
1236135446Strhodes		if (use_cache && view->cachedb != NULL && db != view->hints) {
1237135446Strhodes			/*
1238135446Strhodes			 * We found an answer, but the cache may be better.
1239135446Strhodes			 */
1240135446Strhodes			zfname = dns_fixedname_name(&zfixedname);
1241135446Strhodes			result = dns_name_copy(fname, zfname, NULL);
1242135446Strhodes			if (result != ISC_R_SUCCESS)
1243135446Strhodes				goto cleanup;
1244135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
1245135446Strhodes			dns_rdataset_disassociate(rdataset);
1246135446Strhodes			if (sigrdataset != NULL &&
1247135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
1248135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1249135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1250135446Strhodes			}
1251135446Strhodes			dns_db_detach(&db);
1252135446Strhodes			dns_db_attach(view->cachedb, &db);
1253135446Strhodes			is_cache = ISC_TRUE;
1254135446Strhodes			goto db_find;
1255135446Strhodes		}
1256135446Strhodes	} else {
1257135446Strhodes		result = dns_db_findzonecut(db, name, options, now, NULL,
1258135446Strhodes					    fname, rdataset, sigrdataset);
1259135446Strhodes		if (result == ISC_R_SUCCESS) {
1260135446Strhodes			if (zfname != NULL &&
1261224092Sdougb			    (!dns_name_issubdomain(fname, zfname) ||
1262224092Sdougb			     (dns_zone_staticstub &&
1263224092Sdougb			      dns_name_equal(fname, zfname)))) {
1264135446Strhodes				/*
1265135446Strhodes				 * We found a zonecut in the cache, but our
1266135446Strhodes				 * zone delegation is better.
1267135446Strhodes				 */
1268135446Strhodes				use_zone = ISC_TRUE;
1269135446Strhodes			}
1270135446Strhodes		} else if (result == ISC_R_NOTFOUND) {
1271135446Strhodes			if (zfname != NULL) {
1272135446Strhodes				/*
1273135446Strhodes				 * We didn't find anything in the cache, but we
1274135446Strhodes				 * have a zone delegation, so use it.
1275135446Strhodes				 */
1276135446Strhodes				use_zone = ISC_TRUE;
1277135446Strhodes			} else {
1278135446Strhodes				/*
1279135446Strhodes				 * Maybe we have hints...
1280135446Strhodes				 */
1281135446Strhodes				try_hints = ISC_TRUE;
1282135446Strhodes			}
1283135446Strhodes		} else {
1284135446Strhodes			/*
1285135446Strhodes			 * Something bad happened.
1286135446Strhodes			 */
1287135446Strhodes			goto cleanup;
1288135446Strhodes		}
1289135446Strhodes	}
1290135446Strhodes
1291135446Strhodes finish:
1292135446Strhodes	if (use_zone) {
1293135446Strhodes		if (dns_rdataset_isassociated(rdataset)) {
1294135446Strhodes			dns_rdataset_disassociate(rdataset);
1295135446Strhodes			if (sigrdataset != NULL &&
1296135446Strhodes			    dns_rdataset_isassociated(sigrdataset))
1297135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1298135446Strhodes		}
1299135446Strhodes		result = dns_name_copy(zfname, fname, NULL);
1300135446Strhodes		if (result != ISC_R_SUCCESS)
1301135446Strhodes			goto cleanup;
1302135446Strhodes		dns_rdataset_clone(&zrdataset, rdataset);
1303135446Strhodes		if (sigrdataset != NULL &&
1304135446Strhodes		    dns_rdataset_isassociated(&zrdataset))
1305135446Strhodes			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1306135446Strhodes	} else if (try_hints && use_hints && view->hints != NULL) {
1307135446Strhodes		/*
1308135446Strhodes		 * We've found nothing so far, but we have hints.
1309135446Strhodes		 */
1310135446Strhodes		result = dns_db_find(view->hints, dns_rootname, NULL,
1311135446Strhodes				     dns_rdatatype_ns, 0, now, NULL, fname,
1312135446Strhodes				     rdataset, NULL);
1313135446Strhodes		if (result != ISC_R_SUCCESS) {
1314135446Strhodes			/*
1315135446Strhodes			 * We can't even find the hints for the root
1316135446Strhodes			 * nameservers!
1317135446Strhodes			 */
1318135446Strhodes			if (dns_rdataset_isassociated(rdataset))
1319135446Strhodes				dns_rdataset_disassociate(rdataset);
1320135446Strhodes			result = ISC_R_NOTFOUND;
1321135446Strhodes		}
1322135446Strhodes	}
1323135446Strhodes
1324135446Strhodes cleanup:
1325135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
1326135446Strhodes		dns_rdataset_disassociate(&zrdataset);
1327135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
1328135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
1329135446Strhodes	}
1330135446Strhodes	if (db != NULL)
1331135446Strhodes		dns_db_detach(&db);
1332224092Sdougb#ifdef BIND9
1333135446Strhodes	if (zone != NULL)
1334135446Strhodes		dns_zone_detach(&zone);
1335224092Sdougb#endif
1336135446Strhodes
1337135446Strhodes	return (result);
1338135446Strhodes}
1339135446Strhodes
1340135446Strhodesisc_result_t
1341135446Strhodesdns_viewlist_find(dns_viewlist_t *list, const char *name,
1342135446Strhodes		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1343135446Strhodes{
1344135446Strhodes	dns_view_t *view;
1345135446Strhodes
1346135446Strhodes	REQUIRE(list != NULL);
1347135446Strhodes
1348135446Strhodes	for (view = ISC_LIST_HEAD(*list);
1349135446Strhodes	     view != NULL;
1350135446Strhodes	     view = ISC_LIST_NEXT(view, link)) {
1351135446Strhodes		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1352135446Strhodes			break;
1353135446Strhodes	}
1354135446Strhodes	if (view == NULL)
1355135446Strhodes		return (ISC_R_NOTFOUND);
1356135446Strhodes
1357135446Strhodes	dns_view_attach(view, viewp);
1358135446Strhodes
1359135446Strhodes	return (ISC_R_SUCCESS);
1360135446Strhodes}
1361135446Strhodes
1362224092Sdougb#ifdef BIND9
1363135446Strhodesisc_result_t
1364193149Sdougbdns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1365193149Sdougb		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1366193149Sdougb		      dns_zone_t **zonep)
1367193149Sdougb{
1368193149Sdougb	dns_view_t *view;
1369193149Sdougb	isc_result_t result;
1370193149Sdougb	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1371193149Sdougb	dns_zone_t **zp = NULL;;
1372193149Sdougb
1373193149Sdougb	REQUIRE(list != NULL);
1374193149Sdougb	for (view = ISC_LIST_HEAD(*list);
1375193149Sdougb	     view != NULL;
1376193149Sdougb	     view = ISC_LIST_NEXT(view, link)) {
1377193149Sdougb		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1378193149Sdougb			continue;
1379193149Sdougb
1380193149Sdougb		/*
1381193149Sdougb		 * If the zone is defined in more than one view,
1382193149Sdougb		 * treat it as not found.
1383193149Sdougb		 */
1384193149Sdougb		zp = (zone1 == NULL) ? &zone1 : &zone2;
1385193149Sdougb		result = dns_zt_find(view->zonetable, name, 0, NULL, zp);
1386193149Sdougb		INSIST(result == ISC_R_SUCCESS ||
1387193149Sdougb		       result == ISC_R_NOTFOUND ||
1388193149Sdougb		       result == DNS_R_PARTIALMATCH);
1389193149Sdougb
1390193149Sdougb		/* Treat a partial match as no match */
1391193149Sdougb		if (result == DNS_R_PARTIALMATCH) {
1392193149Sdougb			dns_zone_detach(zp);
1393193149Sdougb			result = ISC_R_NOTFOUND;
1394193149Sdougb		}
1395193149Sdougb
1396193149Sdougb		if (zone2 != NULL) {
1397193149Sdougb			dns_zone_detach(&zone1);
1398193149Sdougb			dns_zone_detach(&zone2);
1399193149Sdougb			return (ISC_R_NOTFOUND);
1400193149Sdougb		}
1401193149Sdougb	}
1402193149Sdougb
1403193149Sdougb	if (zone1 != NULL) {
1404193149Sdougb		dns_zone_attach(zone1, zonep);
1405193149Sdougb		dns_zone_detach(&zone1);
1406193149Sdougb		return (ISC_R_SUCCESS);
1407193149Sdougb	}
1408193149Sdougb
1409193149Sdougb	return (ISC_R_NOTFOUND);
1410193149Sdougb}
1411193149Sdougb
1412193149Sdougbisc_result_t
1413135446Strhodesdns_view_load(dns_view_t *view, isc_boolean_t stop) {
1414135446Strhodes
1415135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1416135446Strhodes
1417135446Strhodes	return (dns_zt_load(view->zonetable, stop));
1418135446Strhodes}
1419135446Strhodes
1420135446Strhodesisc_result_t
1421135446Strhodesdns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1422135446Strhodes
1423135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1424135446Strhodes
1425135446Strhodes	return (dns_zt_loadnew(view->zonetable, stop));
1426135446Strhodes}
1427224092Sdougb#endif /* BIND9 */
1428135446Strhodes
1429135446Strhodesisc_result_t
1430135446Strhodesdns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1431135446Strhodes{
1432135446Strhodes	isc_result_t result;
1433135446Strhodes	REQUIRE(keyp != NULL && *keyp == NULL);
1434135446Strhodes
1435135446Strhodes	result = dns_tsigkey_find(keyp, keyname, NULL,
1436135446Strhodes				  view->statickeys);
1437135446Strhodes	if (result == ISC_R_NOTFOUND)
1438135446Strhodes		result = dns_tsigkey_find(keyp, keyname, NULL,
1439135446Strhodes					  view->dynamickeys);
1440135446Strhodes	return (result);
1441135446Strhodes}
1442135446Strhodes
1443135446Strhodesisc_result_t
1444135446Strhodesdns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1445135446Strhodes		     dns_tsigkey_t **keyp)
1446135446Strhodes{
1447135446Strhodes	isc_result_t result;
1448135446Strhodes	dns_name_t *keyname = NULL;
1449135446Strhodes	dns_peer_t *peer = NULL;
1450135446Strhodes
1451135446Strhodes	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1452135446Strhodes	if (result != ISC_R_SUCCESS)
1453135446Strhodes		return (result);
1454135446Strhodes
1455135446Strhodes	result = dns_peer_getkey(peer, &keyname);
1456135446Strhodes	if (result != ISC_R_SUCCESS)
1457135446Strhodes		return (result);
1458135446Strhodes
1459204619Sdougb	result = dns_view_gettsig(view, keyname, keyp);
1460204619Sdougb	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1461135446Strhodes}
1462135446Strhodes
1463135446Strhodesisc_result_t
1464135446Strhodesdns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1465135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1466135446Strhodes	REQUIRE(source != NULL);
1467135446Strhodes
1468135446Strhodes	return (dns_tsig_verify(source, msg, view->statickeys,
1469135446Strhodes				view->dynamickeys));
1470135446Strhodes}
1471135446Strhodes
1472224092Sdougb#ifdef BIND9
1473135446Strhodesisc_result_t
1474135446Strhodesdns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1475135446Strhodes	isc_result_t result;
1476135446Strhodes
1477135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1478135446Strhodes
1479135446Strhodes	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1480135446Strhodes	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1481205292Sdougb					 &dns_master_style_cache, fp);
1482135446Strhodes	if (result != ISC_R_SUCCESS)
1483135446Strhodes		return (result);
1484135446Strhodes	dns_adb_dump(view->adb, fp);
1485205292Sdougb	dns_resolver_printbadcache(view->resolver, fp);
1486135446Strhodes	return (ISC_R_SUCCESS);
1487135446Strhodes}
1488224092Sdougb#endif
1489135446Strhodes
1490135446Strhodesisc_result_t
1491135446Strhodesdns_view_flushcache(dns_view_t *view) {
1492224092Sdougb	return (dns_view_flushcache2(view, ISC_FALSE));
1493224092Sdougb}
1494224092Sdougb
1495224092Sdougbisc_result_t
1496224092Sdougbdns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1497135446Strhodes	isc_result_t result;
1498135446Strhodes
1499135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1500135446Strhodes
1501135446Strhodes	if (view->cachedb == NULL)
1502135446Strhodes		return (ISC_R_SUCCESS);
1503224092Sdougb	if (!fixuponly) {
1504224092Sdougb		result = dns_cache_flush(view->cache);
1505224092Sdougb		if (result != ISC_R_SUCCESS)
1506224092Sdougb			return (result);
1507224092Sdougb	}
1508224092Sdougb#ifdef BIND9
1509170222Sdougb	if (view->acache != NULL)
1510170222Sdougb		dns_acache_putdb(view->acache, view->cachedb);
1511224092Sdougb#endif
1512135446Strhodes	dns_db_detach(&view->cachedb);
1513135446Strhodes	dns_cache_attachdb(view->cache, &view->cachedb);
1514224092Sdougb#ifdef BIND9
1515170222Sdougb	if (view->acache != NULL)
1516170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
1517205292Sdougb	if (view->resolver != NULL)
1518205292Sdougb		dns_resolver_flushbadcache(view->resolver, NULL);
1519224092Sdougb#endif
1520135446Strhodes
1521135446Strhodes	dns_adb_flush(view->adb);
1522135446Strhodes	return (ISC_R_SUCCESS);
1523135446Strhodes}
1524135446Strhodes
1525135446Strhodesisc_result_t
1526135446Strhodesdns_view_flushname(dns_view_t *view, dns_name_t *name) {
1527135446Strhodes
1528135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1529135446Strhodes
1530135446Strhodes	if (view->adb != NULL)
1531135446Strhodes		dns_adb_flushname(view->adb, name);
1532135446Strhodes	if (view->cache == NULL)
1533135446Strhodes		return (ISC_R_SUCCESS);
1534205292Sdougb	if (view->resolver != NULL)
1535205292Sdougb		dns_resolver_flushbadcache(view->resolver, name);
1536135446Strhodes	return (dns_cache_flushname(view->cache, name));
1537135446Strhodes}
1538135446Strhodes
1539135446Strhodesisc_result_t
1540135446Strhodesdns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1541135446Strhodes	isc_result_t result;
1542135446Strhodes	dns_name_t *new;
1543135446Strhodes	isc_uint32_t hash;
1544135446Strhodes
1545135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1546135446Strhodes
1547135446Strhodes	if (view->delonly == NULL) {
1548135446Strhodes		view->delonly = isc_mem_get(view->mctx,
1549135446Strhodes					    sizeof(dns_namelist_t) *
1550135446Strhodes					    DNS_VIEW_DELONLYHASH);
1551135446Strhodes		if (view->delonly == NULL)
1552135446Strhodes			return (ISC_R_NOMEMORY);
1553135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1554135446Strhodes			ISC_LIST_INIT(view->delonly[hash]);
1555135446Strhodes	}
1556135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1557135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1558135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1559135446Strhodes		new = ISC_LIST_NEXT(new, link);
1560135446Strhodes	if (new != NULL)
1561135446Strhodes		return (ISC_R_SUCCESS);
1562135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1563135446Strhodes	if (new == NULL)
1564135446Strhodes		return (ISC_R_NOMEMORY);
1565135446Strhodes	dns_name_init(new, NULL);
1566135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1567135446Strhodes	if (result == ISC_R_SUCCESS)
1568135446Strhodes		ISC_LIST_APPEND(view->delonly[hash], new, link);
1569135446Strhodes	else
1570135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1571135446Strhodes	return (result);
1572135446Strhodes}
1573135446Strhodes
1574135446Strhodesisc_result_t
1575135446Strhodesdns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1576135446Strhodes	isc_result_t result;
1577135446Strhodes	dns_name_t *new;
1578135446Strhodes	isc_uint32_t hash;
1579135446Strhodes
1580135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1581135446Strhodes
1582135446Strhodes	if (view->rootexclude == NULL) {
1583135446Strhodes		view->rootexclude = isc_mem_get(view->mctx,
1584135446Strhodes					    sizeof(dns_namelist_t) *
1585135446Strhodes					    DNS_VIEW_DELONLYHASH);
1586135446Strhodes		if (view->rootexclude == NULL)
1587135446Strhodes			return (ISC_R_NOMEMORY);
1588135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1589135446Strhodes			ISC_LIST_INIT(view->rootexclude[hash]);
1590135446Strhodes	}
1591135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1592135446Strhodes	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1593135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1594135446Strhodes		new = ISC_LIST_NEXT(new, link);
1595135446Strhodes	if (new != NULL)
1596135446Strhodes		return (ISC_R_SUCCESS);
1597135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1598135446Strhodes	if (new == NULL)
1599135446Strhodes		return (ISC_R_NOMEMORY);
1600135446Strhodes	dns_name_init(new, NULL);
1601135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1602135446Strhodes	if (result == ISC_R_SUCCESS)
1603135446Strhodes		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1604135446Strhodes	else
1605135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1606135446Strhodes	return (result);
1607135446Strhodes}
1608135446Strhodes
1609135446Strhodesisc_boolean_t
1610135446Strhodesdns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1611135446Strhodes	dns_name_t *new;
1612135446Strhodes	isc_uint32_t hash;
1613135446Strhodes
1614135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1615135446Strhodes
1616135446Strhodes	if (!view->rootdelonly && view->delonly == NULL)
1617135446Strhodes		return (ISC_FALSE);
1618135446Strhodes
1619135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1620135446Strhodes	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1621135446Strhodes		if (view->rootexclude == NULL)
1622135446Strhodes			return (ISC_TRUE);
1623135446Strhodes		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1624135446Strhodes		while (new != NULL && !dns_name_equal(new, name))
1625135446Strhodes			new = ISC_LIST_NEXT(new, link);
1626135446Strhodes		if (new == NULL)
1627135446Strhodes			return (ISC_TRUE);
1628135446Strhodes	}
1629135446Strhodes
1630135446Strhodes	if (view->delonly == NULL)
1631135446Strhodes		return (ISC_FALSE);
1632135446Strhodes
1633135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1634135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1635135446Strhodes		new = ISC_LIST_NEXT(new, link);
1636135446Strhodes	if (new == NULL)
1637135446Strhodes		return (ISC_FALSE);
1638135446Strhodes	return (ISC_TRUE);
1639135446Strhodes}
1640135446Strhodes
1641186462Sdougbvoid
1642135446Strhodesdns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1643135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1644135446Strhodes	view->rootdelonly = value;
1645135446Strhodes}
1646135446Strhodes
1647135446Strhodesisc_boolean_t
1648135446Strhodesdns_view_getrootdelonly(dns_view_t *view) {
1649135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1650135446Strhodes	return (view->rootdelonly);
1651135446Strhodes}
1652170222Sdougb
1653224092Sdougb#ifdef BIND9
1654170222Sdougbisc_result_t
1655170222Sdougbdns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1656170222Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1657170222Sdougb	return (dns_zt_freezezones(view->zonetable, value));
1658170222Sdougb}
1659224092Sdougb#endif
1660193149Sdougb
1661193149Sdougbvoid
1662193149Sdougbdns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1663193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1664193149Sdougb	REQUIRE(!view->frozen);
1665193149Sdougb	REQUIRE(view->resstats == NULL);
1666193149Sdougb
1667193149Sdougb	isc_stats_attach(stats, &view->resstats);
1668193149Sdougb}
1669193149Sdougb
1670193149Sdougbvoid
1671193149Sdougbdns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1672193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1673193149Sdougb	REQUIRE(statsp != NULL && *statsp == NULL);
1674193149Sdougb
1675193149Sdougb	if (view->resstats != NULL)
1676193149Sdougb		isc_stats_attach(view->resstats, statsp);
1677193149Sdougb}
1678193149Sdougb
1679193149Sdougbvoid
1680193149Sdougbdns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1681193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1682193149Sdougb	REQUIRE(!view->frozen);
1683193149Sdougb	REQUIRE(view->resquerystats == NULL);
1684193149Sdougb
1685193149Sdougb	dns_stats_attach(stats, &view->resquerystats);
1686193149Sdougb}
1687193149Sdougb
1688193149Sdougbvoid
1689193149Sdougbdns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1690193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1691193149Sdougb	REQUIRE(statsp != NULL && *statsp == NULL);
1692193149Sdougb
1693193149Sdougb	if (view->resquerystats != NULL)
1694193149Sdougb		dns_stats_attach(view->resquerystats, statsp);
1695193149Sdougb}
1696224092Sdougb
1697224092Sdougbisc_result_t
1698224092Sdougbdns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1699224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1700224092Sdougb	if (view->secroots_priv != NULL)
1701224092Sdougb		dns_keytable_detach(&view->secroots_priv);
1702224092Sdougb	return (dns_keytable_create(mctx, &view->secroots_priv));
1703224092Sdougb}
1704224092Sdougb
1705224092Sdougbisc_result_t
1706224092Sdougbdns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1707224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1708224092Sdougb	REQUIRE(ktp != NULL && *ktp == NULL);
1709224092Sdougb	if (view->secroots_priv == NULL)
1710224092Sdougb		return (ISC_R_NOTFOUND);
1711224092Sdougb	dns_keytable_attach(view->secroots_priv, ktp);
1712224092Sdougb	return (ISC_R_SUCCESS);
1713224092Sdougb}
1714224092Sdougb
1715224092Sdougbisc_result_t
1716224092Sdougbdns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1717224092Sdougb			 isc_boolean_t *secure_domain) {
1718224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1719224092Sdougb	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1720224092Sdougb					    secure_domain));
1721224092Sdougb}
1722224092Sdougb
1723224092Sdougbvoid
1724224092Sdougbdns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1725224092Sdougb		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1726224092Sdougb{
1727224092Sdougb	isc_result_t result;
1728224092Sdougb	unsigned char data[4096];
1729224092Sdougb	dns_rdata_t rdata = DNS_RDATA_INIT;
1730224092Sdougb	isc_buffer_t buffer;
1731224092Sdougb	dst_key_t *key = NULL;
1732224092Sdougb	dns_keytable_t *sr = NULL;
1733224092Sdougb
1734224092Sdougb	/*
1735224092Sdougb	 * Clear the revoke bit, if set, so that the key will match what's
1736224092Sdougb	 * in secroots now.
1737224092Sdougb	 */
1738224092Sdougb	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1739224092Sdougb
1740224092Sdougb	/* Convert dnskey to DST key. */
1741224092Sdougb	isc_buffer_init(&buffer, data, sizeof(data));
1742224092Sdougb	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1743224092Sdougb			     dns_rdatatype_dnskey, dnskey, &buffer);
1744224092Sdougb	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1745224092Sdougb	if (result != ISC_R_SUCCESS)
1746224092Sdougb		return;
1747224092Sdougb	result = dns_view_getsecroots(view, &sr);
1748224092Sdougb	if (result == ISC_R_SUCCESS) {
1749224092Sdougb		dns_keytable_deletekeynode(sr, key);
1750224092Sdougb		dns_keytable_detach(&sr);
1751224092Sdougb	}
1752224092Sdougb	dst_key_free(&key);
1753224092Sdougb}
1754224092Sdougb
1755224092Sdougb#define NZF ".nzf"
1756224092Sdougb
1757224092Sdougbvoid
1758224092Sdougbdns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1759224092Sdougb		     void (*cfg_destroy)(void **))
1760224092Sdougb{
1761224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1762224092Sdougb	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1763224092Sdougb
1764224092Sdougb#ifdef BIND9
1765224092Sdougb	if (view->new_zone_file != NULL) {
1766224092Sdougb		isc_mem_free(view->mctx, view->new_zone_file);
1767224092Sdougb		view->new_zone_file = NULL;
1768224092Sdougb	}
1769224092Sdougb
1770224092Sdougb	if (view->new_zone_config != NULL) {
1771224092Sdougb		view->cfg_destroy(&view->new_zone_config);
1772224092Sdougb		view->cfg_destroy = NULL;
1773224092Sdougb	}
1774224092Sdougb
1775224092Sdougb	if (allow) {
1776224092Sdougb		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1777224092Sdougb		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1778224092Sdougb		/* Truncate the hash at 16 chars; full length is overkill */
1779224092Sdougb		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1780224092Sdougb		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1781224092Sdougb		view->new_zone_config = cfgctx;
1782224092Sdougb		view->cfg_destroy = cfg_destroy;
1783224092Sdougb	}
1784224092Sdougb#else
1785224092Sdougb	UNUSED(allow);
1786224092Sdougb	UNUSED(cfgctx);
1787224092Sdougb	UNUSED(cfg_destroy);
1788224092Sdougb#endif
1789224092Sdougb}
1790