view.c revision 186462
1135446Strhodes/*
2186462Sdougb * Copyright (C) 2004-2008  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
18186462Sdougb/* $Id: view.c,v 1.126.18.16 2008/06/17 23:46:03 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <isc/hash.h>
25135446Strhodes#include <isc/task.h>
26135446Strhodes#include <isc/string.h>		/* Required for HP/UX (and others?) */
27135446Strhodes#include <isc/util.h>
28135446Strhodes
29170222Sdougb#include <dns/acache.h>
30135446Strhodes#include <dns/acl.h>
31135446Strhodes#include <dns/adb.h>
32135446Strhodes#include <dns/cache.h>
33135446Strhodes#include <dns/db.h>
34170222Sdougb#include <dns/dlz.h>
35135446Strhodes#include <dns/events.h>
36135446Strhodes#include <dns/forward.h>
37135446Strhodes#include <dns/keytable.h>
38135446Strhodes#include <dns/master.h>
39135446Strhodes#include <dns/masterdump.h>
40135446Strhodes#include <dns/order.h>
41135446Strhodes#include <dns/peer.h>
42135446Strhodes#include <dns/rdataset.h>
43135446Strhodes#include <dns/request.h>
44135446Strhodes#include <dns/resolver.h>
45135446Strhodes#include <dns/result.h>
46135446Strhodes#include <dns/tsig.h>
47135446Strhodes#include <dns/zone.h>
48135446Strhodes#include <dns/zt.h>
49135446Strhodes
50135446Strhodes#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
51135446Strhodes#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
52135446Strhodes#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
53135446Strhodes
54135446Strhodes#define DNS_VIEW_DELONLYHASH 111
55135446Strhodes
56135446Strhodesstatic void resolver_shutdown(isc_task_t *task, isc_event_t *event);
57135446Strhodesstatic void adb_shutdown(isc_task_t *task, isc_event_t *event);
58135446Strhodesstatic void req_shutdown(isc_task_t *task, isc_event_t *event);
59135446Strhodes
60135446Strhodesisc_result_t
61135446Strhodesdns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
62135446Strhodes		const char *name, dns_view_t **viewp)
63135446Strhodes{
64135446Strhodes	dns_view_t *view;
65135446Strhodes	isc_result_t result;
66135446Strhodes
67135446Strhodes	/*
68135446Strhodes	 * Create a view.
69135446Strhodes	 */
70135446Strhodes
71135446Strhodes	REQUIRE(name != NULL);
72135446Strhodes	REQUIRE(viewp != NULL && *viewp == NULL);
73135446Strhodes
74135446Strhodes	view = isc_mem_get(mctx, sizeof(*view));
75135446Strhodes	if (view == NULL)
76135446Strhodes		return (ISC_R_NOMEMORY);
77135446Strhodes	view->name = isc_mem_strdup(mctx, name);
78135446Strhodes	if (view->name == NULL) {
79135446Strhodes		result = ISC_R_NOMEMORY;
80135446Strhodes		goto cleanup_view;
81135446Strhodes	}
82135446Strhodes	result = isc_mutex_init(&view->lock);
83170222Sdougb	if (result != ISC_R_SUCCESS)
84135446Strhodes		goto cleanup_name;
85170222Sdougb
86135446Strhodes	view->zonetable = NULL;
87135446Strhodes	result = dns_zt_create(mctx, rdclass, &view->zonetable);
88135446Strhodes	if (result != ISC_R_SUCCESS) {
89135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
90135446Strhodes				 "dns_zt_create() failed: %s",
91135446Strhodes				 isc_result_totext(result));
92135446Strhodes		result = ISC_R_UNEXPECTED;
93135446Strhodes		goto cleanup_mutex;
94135446Strhodes	}
95135446Strhodes	view->secroots = NULL;
96135446Strhodes	result = dns_keytable_create(mctx, &view->secroots);
97135446Strhodes	if (result != ISC_R_SUCCESS) {
98135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
99135446Strhodes				 "dns_keytable_create() failed: %s",
100135446Strhodes				 isc_result_totext(result));
101135446Strhodes		result = ISC_R_UNEXPECTED;
102135446Strhodes		goto cleanup_zt;
103135446Strhodes	}
104135446Strhodes	view->trustedkeys = NULL;
105135446Strhodes	result = dns_keytable_create(mctx, &view->trustedkeys);
106135446Strhodes	if (result != ISC_R_SUCCESS) {
107135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
108135446Strhodes				 "dns_keytable_create() failed: %s",
109135446Strhodes				 isc_result_totext(result));
110135446Strhodes		result = ISC_R_UNEXPECTED;
111135446Strhodes		goto cleanup_secroots;
112135446Strhodes	}
113135446Strhodes	view->fwdtable = NULL;
114135446Strhodes	result = dns_fwdtable_create(mctx, &view->fwdtable);
115135446Strhodes	if (result != ISC_R_SUCCESS) {
116135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
117135446Strhodes				 "dns_fwdtable_create() failed: %s",
118135446Strhodes				 isc_result_totext(result));
119135446Strhodes		result = ISC_R_UNEXPECTED;
120135446Strhodes		goto cleanup_trustedkeys;
121135446Strhodes	}
122135446Strhodes
123170222Sdougb	view->acache = NULL;
124135446Strhodes	view->cache = NULL;
125135446Strhodes	view->cachedb = NULL;
126170222Sdougb	view->dlzdatabase = NULL;
127135446Strhodes	view->hints = NULL;
128135446Strhodes	view->resolver = NULL;
129135446Strhodes	view->adb = NULL;
130135446Strhodes	view->requestmgr = NULL;
131135446Strhodes	view->mctx = mctx;
132135446Strhodes	view->rdclass = rdclass;
133135446Strhodes	view->frozen = ISC_FALSE;
134135446Strhodes	view->task = NULL;
135170222Sdougb	result = isc_refcount_init(&view->references, 1);
136170222Sdougb	if (result != ISC_R_SUCCESS)
137170222Sdougb		goto cleanup_fwdtable;
138135446Strhodes	view->weakrefs = 0;
139135446Strhodes	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
140135446Strhodes			    DNS_VIEWATTR_REQSHUTDOWN);
141135446Strhodes	view->statickeys = NULL;
142135446Strhodes	view->dynamickeys = NULL;
143135446Strhodes	view->matchclients = NULL;
144135446Strhodes	view->matchdestinations = NULL;
145135446Strhodes	view->matchrecursiveonly = ISC_FALSE;
146135446Strhodes	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
147135446Strhodes	if (result != ISC_R_SUCCESS)
148170222Sdougb		goto cleanup_references;
149135446Strhodes	view->peers = NULL;
150135446Strhodes	view->order = NULL;
151135446Strhodes	view->delonly = NULL;
152135446Strhodes	view->rootdelonly = ISC_FALSE;
153135446Strhodes	view->rootexclude = NULL;
154135446Strhodes
155135446Strhodes	/*
156135446Strhodes	 * Initialize configuration data with default values.
157135446Strhodes	 */
158135446Strhodes	view->recursion = ISC_TRUE;
159135446Strhodes	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
160135446Strhodes	view->additionalfromcache = ISC_TRUE;
161135446Strhodes	view->additionalfromauth = ISC_TRUE;
162135446Strhodes	view->enablednssec = ISC_TRUE;
163170222Sdougb	view->enablevalidation = ISC_TRUE;
164170222Sdougb	view->acceptexpired = ISC_FALSE;
165135446Strhodes	view->minimalresponses = ISC_FALSE;
166135446Strhodes	view->transfer_format = dns_one_answer;
167135446Strhodes	view->queryacl = NULL;
168135446Strhodes	view->recursionacl = NULL;
169135446Strhodes	view->sortlist = NULL;
170135446Strhodes	view->requestixfr = ISC_TRUE;
171135446Strhodes	view->provideixfr = ISC_TRUE;
172135446Strhodes	view->maxcachettl = 7 * 24 * 3600;
173135446Strhodes	view->maxncachettl = 3 * 3600;
174135446Strhodes	view->dstport = 53;
175135446Strhodes	view->preferred_glue = 0;
176135446Strhodes	view->flush = ISC_FALSE;
177135446Strhodes	view->dlv = NULL;
178170222Sdougb	view->maxudp = 0;
179135446Strhodes	dns_fixedname_init(&view->dlv_fixed);
180135446Strhodes
181135446Strhodes	result = dns_order_create(view->mctx, &view->order);
182135446Strhodes	if (result != ISC_R_SUCCESS)
183135446Strhodes		goto cleanup_dynkeys;
184135446Strhodes
185135446Strhodes	result = dns_peerlist_new(view->mctx, &view->peers);
186135446Strhodes	if (result != ISC_R_SUCCESS)
187135446Strhodes		goto cleanup_order;
188135446Strhodes
189135446Strhodes	result = dns_aclenv_init(view->mctx, &view->aclenv);
190135446Strhodes	if (result != ISC_R_SUCCESS)
191135446Strhodes		goto cleanup_peerlist;
192135446Strhodes
193135446Strhodes	ISC_LINK_INIT(view, link);
194135446Strhodes	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
195135446Strhodes		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
196135446Strhodes		       view, NULL, NULL, NULL);
197135446Strhodes	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
198135446Strhodes		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
199135446Strhodes		       view, NULL, NULL, NULL);
200135446Strhodes	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
201135446Strhodes		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
202135446Strhodes		       view, NULL, NULL, NULL);
203135446Strhodes	view->magic = DNS_VIEW_MAGIC;
204135446Strhodes
205135446Strhodes	*viewp = view;
206135446Strhodes
207135446Strhodes	return (ISC_R_SUCCESS);
208135446Strhodes
209135446Strhodes cleanup_peerlist:
210135446Strhodes	dns_peerlist_detach(&view->peers);
211135446Strhodes
212135446Strhodes cleanup_order:
213135446Strhodes	dns_order_detach(&view->order);
214135446Strhodes
215135446Strhodes cleanup_dynkeys:
216135446Strhodes	dns_tsigkeyring_destroy(&view->dynamickeys);
217135446Strhodes
218170222Sdougb cleanup_references:
219170222Sdougb	isc_refcount_destroy(&view->references);
220170222Sdougb
221135446Strhodes cleanup_fwdtable:
222135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
223135446Strhodes
224135446Strhodes cleanup_trustedkeys:
225135446Strhodes	dns_keytable_detach(&view->trustedkeys);
226135446Strhodes
227135446Strhodes cleanup_secroots:
228135446Strhodes	dns_keytable_detach(&view->secroots);
229135446Strhodes
230135446Strhodes cleanup_zt:
231135446Strhodes	dns_zt_detach(&view->zonetable);
232135446Strhodes
233135446Strhodes cleanup_mutex:
234135446Strhodes	DESTROYLOCK(&view->lock);
235135446Strhodes
236135446Strhodes cleanup_name:
237135446Strhodes	isc_mem_free(mctx, view->name);
238135446Strhodes
239135446Strhodes cleanup_view:
240135446Strhodes	isc_mem_put(mctx, view, sizeof(*view));
241135446Strhodes
242135446Strhodes	return (result);
243135446Strhodes}
244135446Strhodes
245135446Strhodesstatic inline void
246135446Strhodesdestroy(dns_view_t *view) {
247135446Strhodes	REQUIRE(!ISC_LINK_LINKED(view, link));
248135446Strhodes	REQUIRE(isc_refcount_current(&view->references) == 0);
249135446Strhodes	REQUIRE(view->weakrefs == 0);
250135446Strhodes	REQUIRE(RESSHUTDOWN(view));
251135446Strhodes	REQUIRE(ADBSHUTDOWN(view));
252135446Strhodes	REQUIRE(REQSHUTDOWN(view));
253135446Strhodes
254135446Strhodes	if (view->order != NULL)
255135446Strhodes		dns_order_detach(&view->order);
256135446Strhodes	if (view->peers != NULL)
257135446Strhodes		dns_peerlist_detach(&view->peers);
258135446Strhodes	if (view->dynamickeys != NULL)
259135446Strhodes		dns_tsigkeyring_destroy(&view->dynamickeys);
260135446Strhodes	if (view->statickeys != NULL)
261135446Strhodes		dns_tsigkeyring_destroy(&view->statickeys);
262135446Strhodes	if (view->adb != NULL)
263135446Strhodes		dns_adb_detach(&view->adb);
264135446Strhodes	if (view->resolver != NULL)
265135446Strhodes		dns_resolver_detach(&view->resolver);
266170222Sdougb	if (view->acache != NULL) {
267170222Sdougb		if (view->cachedb != NULL)
268170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
269170222Sdougb		dns_acache_detach(&view->acache);
270170222Sdougb	}
271135446Strhodes	if (view->requestmgr != NULL)
272135446Strhodes		dns_requestmgr_detach(&view->requestmgr);
273135446Strhodes	if (view->task != NULL)
274135446Strhodes		isc_task_detach(&view->task);
275135446Strhodes	if (view->hints != NULL)
276135446Strhodes		dns_db_detach(&view->hints);
277170222Sdougb	if (view->dlzdatabase != NULL)
278170222Sdougb		dns_dlzdestroy(&view->dlzdatabase);
279135446Strhodes	if (view->cachedb != NULL)
280135446Strhodes		dns_db_detach(&view->cachedb);
281135446Strhodes	if (view->cache != NULL)
282135446Strhodes		dns_cache_detach(&view->cache);
283135446Strhodes	if (view->matchclients != NULL)
284135446Strhodes		dns_acl_detach(&view->matchclients);
285135446Strhodes	if (view->matchdestinations != NULL)
286135446Strhodes		dns_acl_detach(&view->matchdestinations);
287135446Strhodes	if (view->queryacl != NULL)
288135446Strhodes		dns_acl_detach(&view->queryacl);
289135446Strhodes	if (view->recursionacl != NULL)
290135446Strhodes		dns_acl_detach(&view->recursionacl);
291135446Strhodes	if (view->sortlist != NULL)
292135446Strhodes		dns_acl_detach(&view->sortlist);
293135446Strhodes	if (view->delonly != NULL) {
294135446Strhodes		dns_name_t *name;
295135446Strhodes		int i;
296135446Strhodes
297135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
298135446Strhodes			name = ISC_LIST_HEAD(view->delonly[i]);
299135446Strhodes			while (name != NULL) {
300135446Strhodes				ISC_LIST_UNLINK(view->delonly[i], name, link);
301135446Strhodes				dns_name_free(name, view->mctx);
302135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
303135446Strhodes				name = ISC_LIST_HEAD(view->delonly[i]);
304135446Strhodes			}
305135446Strhodes		}
306135446Strhodes		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
307135446Strhodes			    DNS_VIEW_DELONLYHASH);
308135446Strhodes		view->delonly = NULL;
309135446Strhodes	}
310135446Strhodes	if (view->rootexclude != NULL) {
311135446Strhodes		dns_name_t *name;
312135446Strhodes		int i;
313135446Strhodes
314135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
315135446Strhodes			name = ISC_LIST_HEAD(view->rootexclude[i]);
316135446Strhodes			while (name != NULL) {
317135446Strhodes				ISC_LIST_UNLINK(view->rootexclude[i],
318186462Sdougb						name, link);
319135446Strhodes				dns_name_free(name, view->mctx);
320135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
321135446Strhodes				name = ISC_LIST_HEAD(view->rootexclude[i]);
322135446Strhodes			}
323135446Strhodes		}
324135446Strhodes		isc_mem_put(view->mctx, view->rootexclude,
325135446Strhodes			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
326135446Strhodes		view->rootexclude = NULL;
327135446Strhodes	}
328135446Strhodes	dns_keytable_detach(&view->trustedkeys);
329135446Strhodes	dns_keytable_detach(&view->secroots);
330135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
331135446Strhodes	dns_aclenv_destroy(&view->aclenv);
332135446Strhodes	DESTROYLOCK(&view->lock);
333135446Strhodes	isc_refcount_destroy(&view->references);
334135446Strhodes	isc_mem_free(view->mctx, view->name);
335135446Strhodes	isc_mem_put(view->mctx, view, sizeof(*view));
336135446Strhodes}
337135446Strhodes
338135446Strhodes/*
339135446Strhodes * Return true iff 'view' may be freed.
340135446Strhodes * The caller must be holding the view lock.
341135446Strhodes */
342135446Strhodesstatic isc_boolean_t
343135446Strhodesall_done(dns_view_t *view) {
344135446Strhodes
345135446Strhodes	if (isc_refcount_current(&view->references) == 0 &&
346135446Strhodes	    view->weakrefs == 0 &&
347135446Strhodes	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
348135446Strhodes		return (ISC_TRUE);
349135446Strhodes
350135446Strhodes	return (ISC_FALSE);
351135446Strhodes}
352135446Strhodes
353135446Strhodesvoid
354135446Strhodesdns_view_attach(dns_view_t *source, dns_view_t **targetp) {
355135446Strhodes
356135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
357135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
358135446Strhodes
359135446Strhodes	isc_refcount_increment(&source->references, NULL);
360135446Strhodes
361135446Strhodes	*targetp = source;
362135446Strhodes}
363135446Strhodes
364135446Strhodesstatic void
365135446Strhodesview_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
366135446Strhodes	dns_view_t *view;
367135446Strhodes	unsigned int refs;
368135446Strhodes	isc_boolean_t done = ISC_FALSE;
369135446Strhodes
370135446Strhodes	REQUIRE(viewp != NULL);
371135446Strhodes	view = *viewp;
372135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
373135446Strhodes
374135446Strhodes	if (flush)
375135446Strhodes		view->flush = ISC_TRUE;
376135446Strhodes	isc_refcount_decrement(&view->references, &refs);
377135446Strhodes	if (refs == 0) {
378135446Strhodes		LOCK(&view->lock);
379135446Strhodes		if (!RESSHUTDOWN(view))
380135446Strhodes			dns_resolver_shutdown(view->resolver);
381135446Strhodes		if (!ADBSHUTDOWN(view))
382135446Strhodes			dns_adb_shutdown(view->adb);
383135446Strhodes		if (!REQSHUTDOWN(view))
384135446Strhodes			dns_requestmgr_shutdown(view->requestmgr);
385170222Sdougb		if (view->acache != NULL)
386170222Sdougb			dns_acache_shutdown(view->acache);
387135446Strhodes		if (view->flush)
388135446Strhodes			dns_zt_flushanddetach(&view->zonetable);
389135446Strhodes		else
390135446Strhodes			dns_zt_detach(&view->zonetable);
391135446Strhodes		done = all_done(view);
392135446Strhodes		UNLOCK(&view->lock);
393135446Strhodes	}
394135446Strhodes
395135446Strhodes	*viewp = NULL;
396135446Strhodes
397135446Strhodes	if (done)
398135446Strhodes		destroy(view);
399135446Strhodes}
400135446Strhodes
401135446Strhodesvoid
402135446Strhodesdns_view_flushanddetach(dns_view_t **viewp) {
403135446Strhodes	view_flushanddetach(viewp, ISC_TRUE);
404135446Strhodes}
405135446Strhodes
406135446Strhodesvoid
407135446Strhodesdns_view_detach(dns_view_t **viewp) {
408135446Strhodes	view_flushanddetach(viewp, ISC_FALSE);
409135446Strhodes}
410135446Strhodes
411135446Strhodesstatic isc_result_t
412135446Strhodesdialup(dns_zone_t *zone, void *dummy) {
413135446Strhodes	UNUSED(dummy);
414135446Strhodes	dns_zone_dialup(zone);
415135446Strhodes	return (ISC_R_SUCCESS);
416135446Strhodes}
417135446Strhodes
418135446Strhodesvoid
419135446Strhodesdns_view_dialup(dns_view_t *view) {
420135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
421135446Strhodes	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
422135446Strhodes}
423135446Strhodes
424135446Strhodesvoid
425135446Strhodesdns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
426135446Strhodes
427135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
428135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
429135446Strhodes
430135446Strhodes	LOCK(&source->lock);
431135446Strhodes	source->weakrefs++;
432135446Strhodes	UNLOCK(&source->lock);
433135446Strhodes
434135446Strhodes	*targetp = source;
435135446Strhodes}
436135446Strhodes
437135446Strhodesvoid
438135446Strhodesdns_view_weakdetach(dns_view_t **viewp) {
439135446Strhodes	dns_view_t *view;
440135446Strhodes	isc_boolean_t done = ISC_FALSE;
441135446Strhodes
442135446Strhodes	REQUIRE(viewp != NULL);
443135446Strhodes	view = *viewp;
444135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
445135446Strhodes
446135446Strhodes	LOCK(&view->lock);
447135446Strhodes
448135446Strhodes	INSIST(view->weakrefs > 0);
449135446Strhodes	view->weakrefs--;
450135446Strhodes	done = all_done(view);
451135446Strhodes
452135446Strhodes	UNLOCK(&view->lock);
453135446Strhodes
454135446Strhodes	*viewp = NULL;
455135446Strhodes
456135446Strhodes	if (done)
457135446Strhodes		destroy(view);
458135446Strhodes}
459135446Strhodes
460135446Strhodesstatic void
461135446Strhodesresolver_shutdown(isc_task_t *task, isc_event_t *event) {
462135446Strhodes	dns_view_t *view = event->ev_arg;
463135446Strhodes	isc_boolean_t done;
464135446Strhodes
465135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
466135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
467135446Strhodes	REQUIRE(view->task == task);
468135446Strhodes
469135446Strhodes	UNUSED(task);
470135446Strhodes
471135446Strhodes	LOCK(&view->lock);
472135446Strhodes
473135446Strhodes	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
474135446Strhodes	done = all_done(view);
475135446Strhodes
476135446Strhodes	UNLOCK(&view->lock);
477135446Strhodes
478135446Strhodes	isc_event_free(&event);
479135446Strhodes
480135446Strhodes	if (done)
481135446Strhodes		destroy(view);
482135446Strhodes}
483135446Strhodes
484135446Strhodesstatic void
485135446Strhodesadb_shutdown(isc_task_t *task, isc_event_t *event) {
486135446Strhodes	dns_view_t *view = event->ev_arg;
487135446Strhodes	isc_boolean_t done;
488135446Strhodes
489135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
490135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
491135446Strhodes	REQUIRE(view->task == task);
492135446Strhodes
493135446Strhodes	UNUSED(task);
494135446Strhodes
495135446Strhodes	LOCK(&view->lock);
496135446Strhodes
497135446Strhodes	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
498135446Strhodes	done = all_done(view);
499135446Strhodes
500135446Strhodes	UNLOCK(&view->lock);
501135446Strhodes
502135446Strhodes	isc_event_free(&event);
503135446Strhodes
504135446Strhodes	if (done)
505135446Strhodes		destroy(view);
506135446Strhodes}
507135446Strhodes
508135446Strhodesstatic void
509135446Strhodesreq_shutdown(isc_task_t *task, isc_event_t *event) {
510135446Strhodes	dns_view_t *view = event->ev_arg;
511135446Strhodes	isc_boolean_t done;
512135446Strhodes
513135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
514135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
515135446Strhodes	REQUIRE(view->task == task);
516135446Strhodes
517135446Strhodes	UNUSED(task);
518135446Strhodes
519135446Strhodes	LOCK(&view->lock);
520135446Strhodes
521135446Strhodes	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
522135446Strhodes	done = all_done(view);
523135446Strhodes
524135446Strhodes	UNLOCK(&view->lock);
525135446Strhodes
526135446Strhodes	isc_event_free(&event);
527135446Strhodes
528135446Strhodes	if (done)
529135446Strhodes		destroy(view);
530135446Strhodes}
531135446Strhodes
532135446Strhodesisc_result_t
533135446Strhodesdns_view_createresolver(dns_view_t *view,
534135446Strhodes			isc_taskmgr_t *taskmgr, unsigned int ntasks,
535135446Strhodes			isc_socketmgr_t *socketmgr,
536135446Strhodes			isc_timermgr_t *timermgr,
537135446Strhodes			unsigned int options,
538135446Strhodes			dns_dispatchmgr_t *dispatchmgr,
539135446Strhodes			dns_dispatch_t *dispatchv4,
540135446Strhodes			dns_dispatch_t *dispatchv6)
541135446Strhodes{
542135446Strhodes	isc_result_t result;
543135446Strhodes	isc_event_t *event;
544135446Strhodes	isc_mem_t *mctx = NULL;
545135446Strhodes
546135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
547135446Strhodes	REQUIRE(!view->frozen);
548135446Strhodes	REQUIRE(view->resolver == NULL);
549135446Strhodes
550135446Strhodes	result = isc_task_create(taskmgr, 0, &view->task);
551135446Strhodes	if (result != ISC_R_SUCCESS)
552135446Strhodes		return (result);
553135446Strhodes	isc_task_setname(view->task, "view", view);
554135446Strhodes
555135446Strhodes	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
556135446Strhodes				     timermgr, options, dispatchmgr,
557135446Strhodes				     dispatchv4, dispatchv6,
558135446Strhodes				     &view->resolver);
559135446Strhodes	if (result != ISC_R_SUCCESS) {
560135446Strhodes		isc_task_detach(&view->task);
561135446Strhodes		return (result);
562135446Strhodes	}
563135446Strhodes	event = &view->resevent;
564135446Strhodes	dns_resolver_whenshutdown(view->resolver, view->task, &event);
565135446Strhodes	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
566135446Strhodes
567135446Strhodes	result = isc_mem_create(0, 0, &mctx);
568135446Strhodes	if (result != ISC_R_SUCCESS) {
569135446Strhodes		dns_resolver_shutdown(view->resolver);
570135446Strhodes		return (result);
571135446Strhodes	}
572135446Strhodes
573135446Strhodes	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
574135446Strhodes	isc_mem_detach(&mctx);
575135446Strhodes	if (result != ISC_R_SUCCESS) {
576135446Strhodes		dns_resolver_shutdown(view->resolver);
577135446Strhodes		return (result);
578135446Strhodes	}
579135446Strhodes	event = &view->adbevent;
580135446Strhodes	dns_adb_whenshutdown(view->adb, view->task, &event);
581135446Strhodes	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
582135446Strhodes
583135446Strhodes	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
584135446Strhodes				      dns_resolver_taskmgr(view->resolver),
585135446Strhodes				      dns_resolver_dispatchmgr(view->resolver),
586135446Strhodes				      dns_resolver_dispatchv4(view->resolver),
587135446Strhodes				      dns_resolver_dispatchv6(view->resolver),
588135446Strhodes				      &view->requestmgr);
589135446Strhodes	if (result != ISC_R_SUCCESS) {
590135446Strhodes		dns_adb_shutdown(view->adb);
591135446Strhodes		dns_resolver_shutdown(view->resolver);
592135446Strhodes		return (result);
593135446Strhodes	}
594135446Strhodes	event = &view->reqevent;
595135446Strhodes	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
596135446Strhodes	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
597135446Strhodes
598135446Strhodes	return (ISC_R_SUCCESS);
599135446Strhodes}
600135446Strhodes
601135446Strhodesvoid
602135446Strhodesdns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
603135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
604135446Strhodes	REQUIRE(!view->frozen);
605135446Strhodes
606135446Strhodes	if (view->cache != NULL) {
607170222Sdougb		if (view->acache != NULL)
608170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
609135446Strhodes		dns_db_detach(&view->cachedb);
610135446Strhodes		dns_cache_detach(&view->cache);
611135446Strhodes	}
612135446Strhodes	dns_cache_attach(cache, &view->cache);
613135446Strhodes	dns_cache_attachdb(cache, &view->cachedb);
614135446Strhodes	INSIST(DNS_DB_VALID(view->cachedb));
615170222Sdougb
616170222Sdougb	if (view->acache != NULL)
617170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
618135446Strhodes}
619135446Strhodes
620135446Strhodesvoid
621135446Strhodesdns_view_sethints(dns_view_t *view, dns_db_t *hints) {
622135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
623135446Strhodes	REQUIRE(!view->frozen);
624135446Strhodes	REQUIRE(view->hints == NULL);
625135446Strhodes	REQUIRE(dns_db_iszone(hints));
626135446Strhodes
627135446Strhodes	dns_db_attach(hints, &view->hints);
628135446Strhodes}
629135446Strhodes
630135446Strhodesvoid
631135446Strhodesdns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
632135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
633135446Strhodes	REQUIRE(ring != NULL);
634135446Strhodes	if (view->statickeys != NULL)
635135446Strhodes		dns_tsigkeyring_destroy(&view->statickeys);
636135446Strhodes	view->statickeys = ring;
637135446Strhodes}
638135446Strhodes
639135446Strhodesvoid
640135446Strhodesdns_view_setdstport(dns_view_t *view, in_port_t dstport) {
641135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
642135446Strhodes	view->dstport = dstport;
643135446Strhodes}
644135446Strhodes
645135446Strhodesisc_result_t
646135446Strhodesdns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
647135446Strhodes	isc_result_t result;
648135446Strhodes
649135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
650135446Strhodes	REQUIRE(!view->frozen);
651135446Strhodes
652135446Strhodes	result = dns_zt_mount(view->zonetable, zone);
653135446Strhodes
654135446Strhodes	return (result);
655135446Strhodes}
656135446Strhodes
657135446Strhodesvoid
658135446Strhodesdns_view_freeze(dns_view_t *view) {
659135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
660135446Strhodes	REQUIRE(!view->frozen);
661135446Strhodes
662135446Strhodes	if (view->resolver != NULL) {
663135446Strhodes		INSIST(view->cachedb != NULL);
664135446Strhodes		dns_resolver_freeze(view->resolver);
665135446Strhodes	}
666135446Strhodes	view->frozen = ISC_TRUE;
667135446Strhodes}
668135446Strhodes
669135446Strhodesisc_result_t
670135446Strhodesdns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
671135446Strhodes	isc_result_t result;
672135446Strhodes
673135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
674135446Strhodes
675135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
676135446Strhodes	if (result == DNS_R_PARTIALMATCH) {
677135446Strhodes		dns_zone_detach(zonep);
678135446Strhodes		result = ISC_R_NOTFOUND;
679135446Strhodes	}
680135446Strhodes
681135446Strhodes	return (result);
682135446Strhodes}
683135446Strhodes
684135446Strhodesisc_result_t
685135446Strhodesdns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
686135446Strhodes	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
687135446Strhodes	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
688135446Strhodes	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
689135446Strhodes{
690135446Strhodes	isc_result_t result;
691135446Strhodes	dns_db_t *db, *zdb;
692135446Strhodes	dns_dbnode_t *node, *znode;
693135446Strhodes	isc_boolean_t is_cache;
694135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
695135446Strhodes	dns_zone_t *zone;
696135446Strhodes
697135446Strhodes	/*
698135446Strhodes	 * Find an rdataset whose owner name is 'name', and whose type is
699135446Strhodes	 * 'type'.
700135446Strhodes	 */
701135446Strhodes
702135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
703135446Strhodes	REQUIRE(view->frozen);
704135446Strhodes	REQUIRE(type != dns_rdatatype_rrsig);
705135446Strhodes	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
706174187Sdougb	REQUIRE(nodep == NULL || *nodep == NULL);
707135446Strhodes
708135446Strhodes	/*
709135446Strhodes	 * Initialize.
710135446Strhodes	 */
711135446Strhodes	dns_rdataset_init(&zrdataset);
712135446Strhodes	dns_rdataset_init(&zsigrdataset);
713135446Strhodes	zdb = NULL;
714135446Strhodes	znode = NULL;
715135446Strhodes
716135446Strhodes	/*
717135446Strhodes	 * Find a database to answer the query.
718135446Strhodes	 */
719135446Strhodes	zone = NULL;
720135446Strhodes	db = NULL;
721135446Strhodes	node = NULL;
722135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
723135446Strhodes	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
724135446Strhodes		result = dns_zone_getdb(zone, &db);
725135446Strhodes		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
726135446Strhodes			dns_db_attach(view->cachedb, &db);
727135446Strhodes		else if (result != ISC_R_SUCCESS)
728135446Strhodes			goto cleanup;
729135446Strhodes	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
730135446Strhodes		dns_db_attach(view->cachedb, &db);
731135446Strhodes	else
732135446Strhodes		goto cleanup;
733135446Strhodes
734135446Strhodes	is_cache = dns_db_iscache(db);
735135446Strhodes
736135446Strhodes db_find:
737135446Strhodes	/*
738135446Strhodes	 * Now look for an answer in the database.
739135446Strhodes	 */
740135446Strhodes	result = dns_db_find(db, name, NULL, type, options,
741135446Strhodes			     now, &node, foundname, rdataset, sigrdataset);
742135446Strhodes
743135446Strhodes	if (result == DNS_R_DELEGATION ||
744135446Strhodes	    result == ISC_R_NOTFOUND) {
745135446Strhodes		if (dns_rdataset_isassociated(rdataset))
746135446Strhodes			dns_rdataset_disassociate(rdataset);
747135446Strhodes		if (sigrdataset != NULL &&
748135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
749135446Strhodes			dns_rdataset_disassociate(sigrdataset);
750135446Strhodes		if (node != NULL)
751135446Strhodes			dns_db_detachnode(db, &node);
752135446Strhodes		if (!is_cache) {
753135446Strhodes			dns_db_detach(&db);
754135446Strhodes			if (view->cachedb != NULL) {
755135446Strhodes				/*
756135446Strhodes				 * Either the answer is in the cache, or we
757135446Strhodes				 * don't know it.
758135446Strhodes				 */
759135446Strhodes				is_cache = ISC_TRUE;
760135446Strhodes				dns_db_attach(view->cachedb, &db);
761135446Strhodes				goto db_find;
762135446Strhodes			}
763135446Strhodes		} else {
764135446Strhodes			/*
765135446Strhodes			 * We don't have the data in the cache.  If we've got
766135446Strhodes			 * glue from the zone, use it.
767135446Strhodes			 */
768135446Strhodes			if (dns_rdataset_isassociated(&zrdataset)) {
769135446Strhodes				dns_rdataset_clone(&zrdataset, rdataset);
770135446Strhodes				if (sigrdataset != NULL &&
771135446Strhodes				    dns_rdataset_isassociated(&zsigrdataset))
772135446Strhodes					dns_rdataset_clone(&zsigrdataset,
773135446Strhodes							   sigrdataset);
774135446Strhodes				result = DNS_R_GLUE;
775135446Strhodes				if (db != NULL)
776135446Strhodes					dns_db_detach(&db);
777135446Strhodes				dns_db_attach(zdb, &db);
778135446Strhodes				dns_db_attachnode(db, znode, &node);
779135446Strhodes				goto cleanup;
780135446Strhodes			}
781135446Strhodes		}
782135446Strhodes		/*
783135446Strhodes		 * We don't know the answer.
784135446Strhodes		 */
785135446Strhodes		result = ISC_R_NOTFOUND;
786135446Strhodes	} else if (result == DNS_R_GLUE) {
787135446Strhodes		if (view->cachedb != NULL) {
788135446Strhodes			/*
789135446Strhodes			 * We found an answer, but the cache may be better.
790135446Strhodes			 * Remember what we've got and go look in the cache.
791135446Strhodes			 */
792135446Strhodes			is_cache = ISC_TRUE;
793135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
794135446Strhodes			dns_rdataset_disassociate(rdataset);
795135446Strhodes			if (sigrdataset != NULL &&
796135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
797135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
798135446Strhodes				dns_rdataset_disassociate(sigrdataset);
799135446Strhodes			}
800135446Strhodes			dns_db_attach(db, &zdb);
801135446Strhodes			dns_db_attachnode(zdb, node, &znode);
802135446Strhodes			dns_db_detachnode(db, &node);
803135446Strhodes			dns_db_detach(&db);
804135446Strhodes			dns_db_attach(view->cachedb, &db);
805135446Strhodes			goto db_find;
806135446Strhodes		}
807135446Strhodes		/*
808135446Strhodes		 * Otherwise, the glue is the best answer.
809135446Strhodes		 */
810135446Strhodes		result = ISC_R_SUCCESS;
811135446Strhodes	}
812135446Strhodes
813135446Strhodes	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
814135446Strhodes		if (dns_rdataset_isassociated(rdataset))
815135446Strhodes			dns_rdataset_disassociate(rdataset);
816135446Strhodes		if (sigrdataset != NULL &&
817135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
818135446Strhodes			dns_rdataset_disassociate(sigrdataset);
819135446Strhodes		if (db != NULL) {
820135446Strhodes			if (node != NULL)
821135446Strhodes				dns_db_detachnode(db, &node);
822135446Strhodes			dns_db_detach(&db);
823135446Strhodes		}
824135446Strhodes		result = dns_db_find(view->hints, name, NULL, type, options,
825135446Strhodes				     now, &node, foundname,
826135446Strhodes				     rdataset, sigrdataset);
827135446Strhodes		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
828135446Strhodes			/*
829135446Strhodes			 * We just used a hint.  Let the resolver know it
830135446Strhodes			 * should consider priming.
831135446Strhodes			 */
832135446Strhodes			dns_resolver_prime(view->resolver);
833135446Strhodes			dns_db_attach(view->hints, &db);
834135446Strhodes			result = DNS_R_HINT;
835135446Strhodes		} else if (result == DNS_R_NXRRSET) {
836135446Strhodes			dns_db_attach(view->hints, &db);
837135446Strhodes			result = DNS_R_HINTNXRRSET;
838135446Strhodes		} else if (result == DNS_R_NXDOMAIN)
839135446Strhodes			result = ISC_R_NOTFOUND;
840135446Strhodes
841135446Strhodes		/*
842135446Strhodes		 * Cleanup if non-standard hints are used.
843135446Strhodes		 */
844135446Strhodes		if (db == NULL && node != NULL)
845135446Strhodes			dns_db_detachnode(view->hints, &node);
846135446Strhodes	}
847135446Strhodes
848135446Strhodes cleanup:
849135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
850135446Strhodes		dns_rdataset_disassociate(&zrdataset);
851135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
852135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
853135446Strhodes	}
854135446Strhodes
855135446Strhodes	if (zdb != NULL) {
856135446Strhodes		if (znode != NULL)
857135446Strhodes			dns_db_detachnode(zdb, &znode);
858135446Strhodes		dns_db_detach(&zdb);
859135446Strhodes	}
860135446Strhodes
861135446Strhodes	if (db != NULL) {
862135446Strhodes		if (node != NULL) {
863135446Strhodes			if (nodep != NULL)
864135446Strhodes				*nodep = node;
865135446Strhodes			else
866135446Strhodes				dns_db_detachnode(db, &node);
867135446Strhodes		}
868135446Strhodes		if (dbp != NULL)
869135446Strhodes			*dbp = db;
870135446Strhodes		else
871135446Strhodes			dns_db_detach(&db);
872135446Strhodes	} else
873135446Strhodes		INSIST(node == NULL);
874135446Strhodes
875135446Strhodes	if (zone != NULL)
876135446Strhodes		dns_zone_detach(&zone);
877135446Strhodes
878135446Strhodes	return (result);
879135446Strhodes}
880135446Strhodes
881135446Strhodesisc_result_t
882135446Strhodesdns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
883135446Strhodes		    isc_stdtime_t now, unsigned int options,
884135446Strhodes		    isc_boolean_t use_hints,
885135446Strhodes		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
886135446Strhodes{
887135446Strhodes	isc_result_t result;
888135446Strhodes	dns_fixedname_t foundname;
889135446Strhodes
890135446Strhodes	dns_fixedname_init(&foundname);
891135446Strhodes	result = dns_view_find(view, name, type, now, options, use_hints,
892135446Strhodes			       NULL, NULL, dns_fixedname_name(&foundname),
893135446Strhodes			       rdataset, sigrdataset);
894135446Strhodes	if (result == DNS_R_NXDOMAIN) {
895135446Strhodes		/*
896135446Strhodes		 * The rdataset and sigrdataset of the relevant NSEC record
897135446Strhodes		 * may be returned, but the caller cannot use them because
898135446Strhodes		 * foundname is not returned by this simplified API.  We
899135446Strhodes		 * disassociate them here to prevent any misuse by the caller.
900135446Strhodes		 */
901135446Strhodes		if (dns_rdataset_isassociated(rdataset))
902135446Strhodes			dns_rdataset_disassociate(rdataset);
903135446Strhodes		if (sigrdataset != NULL &&
904135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
905135446Strhodes			dns_rdataset_disassociate(sigrdataset);
906135446Strhodes	} else if (result != ISC_R_SUCCESS &&
907135446Strhodes		   result != DNS_R_GLUE &&
908135446Strhodes		   result != DNS_R_HINT &&
909135446Strhodes		   result != DNS_R_NCACHENXDOMAIN &&
910135446Strhodes		   result != DNS_R_NCACHENXRRSET &&
911135446Strhodes		   result != DNS_R_NXRRSET &&
912135446Strhodes		   result != DNS_R_HINTNXRRSET &&
913135446Strhodes		   result != ISC_R_NOTFOUND) {
914135446Strhodes		if (dns_rdataset_isassociated(rdataset))
915135446Strhodes			dns_rdataset_disassociate(rdataset);
916135446Strhodes		if (sigrdataset != NULL &&
917135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
918135446Strhodes			dns_rdataset_disassociate(sigrdataset);
919135446Strhodes		result = ISC_R_NOTFOUND;
920135446Strhodes	}
921135446Strhodes
922135446Strhodes	return (result);
923135446Strhodes}
924135446Strhodes
925135446Strhodesisc_result_t
926135446Strhodesdns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
927135446Strhodes		     isc_stdtime_t now, unsigned int options,
928186462Sdougb		     isc_boolean_t use_hints,
929135446Strhodes		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
930135446Strhodes{
931135446Strhodes	return(dns_view_findzonecut2(view, name, fname, now, options,
932135446Strhodes				     use_hints, ISC_TRUE,
933135446Strhodes				     rdataset, sigrdataset));
934135446Strhodes}
935135446Strhodes
936135446Strhodesisc_result_t
937135446Strhodesdns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
938135446Strhodes		      isc_stdtime_t now, unsigned int options,
939135446Strhodes		      isc_boolean_t use_hints,  isc_boolean_t use_cache,
940135446Strhodes		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
941135446Strhodes{
942135446Strhodes	isc_result_t result;
943135446Strhodes	dns_db_t *db;
944135446Strhodes	isc_boolean_t is_cache, use_zone, try_hints;
945135446Strhodes	dns_zone_t *zone;
946135446Strhodes	dns_name_t *zfname;
947135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
948135446Strhodes	dns_fixedname_t zfixedname;
949135446Strhodes
950135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
951135446Strhodes	REQUIRE(view->frozen);
952135446Strhodes
953135446Strhodes	db = NULL;
954135446Strhodes	zone = NULL;
955135446Strhodes	use_zone = ISC_FALSE;
956135446Strhodes	try_hints = ISC_FALSE;
957135446Strhodes	zfname = NULL;
958135446Strhodes
959135446Strhodes	/*
960135446Strhodes	 * Initialize.
961135446Strhodes	 */
962135446Strhodes	dns_fixedname_init(&zfixedname);
963135446Strhodes	dns_rdataset_init(&zrdataset);
964135446Strhodes	dns_rdataset_init(&zsigrdataset);
965135446Strhodes
966135446Strhodes	/*
967135446Strhodes	 * Find the right database.
968135446Strhodes	 */
969135446Strhodes	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
970135446Strhodes	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
971135446Strhodes		result = dns_zone_getdb(zone, &db);
972135446Strhodes	if (result == ISC_R_NOTFOUND) {
973135446Strhodes		/*
974135446Strhodes		 * We're not directly authoritative for this query name, nor
975135446Strhodes		 * is it a subdomain of any zone for which we're
976135446Strhodes		 * authoritative.
977135446Strhodes		 */
978135446Strhodes		if (use_cache && view->cachedb != NULL) {
979135446Strhodes			/*
980135446Strhodes			 * We have a cache; try it.
981135446Strhodes			 */
982135446Strhodes			dns_db_attach(view->cachedb, &db);
983135446Strhodes		} else {
984135446Strhodes			/*
985135446Strhodes			 * Maybe we have hints...
986135446Strhodes			 */
987135446Strhodes			try_hints = ISC_TRUE;
988135446Strhodes			goto finish;
989135446Strhodes		}
990135446Strhodes	} else if (result != ISC_R_SUCCESS) {
991135446Strhodes		/*
992135446Strhodes		 * Something is broken.
993135446Strhodes		 */
994135446Strhodes		goto cleanup;
995135446Strhodes	}
996135446Strhodes	is_cache = dns_db_iscache(db);
997135446Strhodes
998135446Strhodes db_find:
999135446Strhodes	/*
1000135446Strhodes	 * Look for the zonecut.
1001135446Strhodes	 */
1002135446Strhodes	if (!is_cache) {
1003135446Strhodes		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1004135446Strhodes				     now, NULL, fname, rdataset, sigrdataset);
1005135446Strhodes		if (result == DNS_R_DELEGATION)
1006135446Strhodes			result = ISC_R_SUCCESS;
1007135446Strhodes		else if (result != ISC_R_SUCCESS)
1008135446Strhodes			goto cleanup;
1009135446Strhodes		if (use_cache && view->cachedb != NULL && db != view->hints) {
1010135446Strhodes			/*
1011135446Strhodes			 * We found an answer, but the cache may be better.
1012135446Strhodes			 */
1013135446Strhodes			zfname = dns_fixedname_name(&zfixedname);
1014135446Strhodes			result = dns_name_copy(fname, zfname, NULL);
1015135446Strhodes			if (result != ISC_R_SUCCESS)
1016135446Strhodes				goto cleanup;
1017135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
1018135446Strhodes			dns_rdataset_disassociate(rdataset);
1019135446Strhodes			if (sigrdataset != NULL &&
1020135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
1021135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1022135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1023135446Strhodes			}
1024135446Strhodes			dns_db_detach(&db);
1025135446Strhodes			dns_db_attach(view->cachedb, &db);
1026135446Strhodes			is_cache = ISC_TRUE;
1027135446Strhodes			goto db_find;
1028135446Strhodes		}
1029135446Strhodes	} else {
1030135446Strhodes		result = dns_db_findzonecut(db, name, options, now, NULL,
1031135446Strhodes					    fname, rdataset, sigrdataset);
1032135446Strhodes		if (result == ISC_R_SUCCESS) {
1033135446Strhodes			if (zfname != NULL &&
1034135446Strhodes			    !dns_name_issubdomain(fname, zfname)) {
1035135446Strhodes				/*
1036135446Strhodes				 * We found a zonecut in the cache, but our
1037135446Strhodes				 * zone delegation is better.
1038135446Strhodes				 */
1039135446Strhodes				use_zone = ISC_TRUE;
1040135446Strhodes			}
1041135446Strhodes		} else if (result == ISC_R_NOTFOUND) {
1042135446Strhodes			if (zfname != NULL) {
1043135446Strhodes				/*
1044135446Strhodes				 * We didn't find anything in the cache, but we
1045135446Strhodes				 * have a zone delegation, so use it.
1046135446Strhodes				 */
1047135446Strhodes				use_zone = ISC_TRUE;
1048135446Strhodes			} else {
1049135446Strhodes				/*
1050135446Strhodes				 * Maybe we have hints...
1051135446Strhodes				 */
1052135446Strhodes				try_hints = ISC_TRUE;
1053135446Strhodes			}
1054135446Strhodes		} else {
1055135446Strhodes			/*
1056135446Strhodes			 * Something bad happened.
1057135446Strhodes			 */
1058135446Strhodes			goto cleanup;
1059135446Strhodes		}
1060135446Strhodes	}
1061135446Strhodes
1062135446Strhodes finish:
1063135446Strhodes	if (use_zone) {
1064135446Strhodes		if (dns_rdataset_isassociated(rdataset)) {
1065135446Strhodes			dns_rdataset_disassociate(rdataset);
1066135446Strhodes			if (sigrdataset != NULL &&
1067135446Strhodes			    dns_rdataset_isassociated(sigrdataset))
1068135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1069135446Strhodes		}
1070135446Strhodes		result = dns_name_copy(zfname, fname, NULL);
1071135446Strhodes		if (result != ISC_R_SUCCESS)
1072135446Strhodes			goto cleanup;
1073135446Strhodes		dns_rdataset_clone(&zrdataset, rdataset);
1074135446Strhodes		if (sigrdataset != NULL &&
1075135446Strhodes		    dns_rdataset_isassociated(&zrdataset))
1076135446Strhodes			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1077135446Strhodes	} else if (try_hints && use_hints && view->hints != NULL) {
1078135446Strhodes		/*
1079135446Strhodes		 * We've found nothing so far, but we have hints.
1080135446Strhodes		 */
1081135446Strhodes		result = dns_db_find(view->hints, dns_rootname, NULL,
1082135446Strhodes				     dns_rdatatype_ns, 0, now, NULL, fname,
1083135446Strhodes				     rdataset, NULL);
1084135446Strhodes		if (result != ISC_R_SUCCESS) {
1085135446Strhodes			/*
1086135446Strhodes			 * We can't even find the hints for the root
1087135446Strhodes			 * nameservers!
1088135446Strhodes			 */
1089135446Strhodes			if (dns_rdataset_isassociated(rdataset))
1090135446Strhodes				dns_rdataset_disassociate(rdataset);
1091135446Strhodes			result = ISC_R_NOTFOUND;
1092135446Strhodes		}
1093135446Strhodes	}
1094135446Strhodes
1095135446Strhodes cleanup:
1096135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
1097135446Strhodes		dns_rdataset_disassociate(&zrdataset);
1098135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
1099135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
1100135446Strhodes	}
1101135446Strhodes	if (db != NULL)
1102135446Strhodes		dns_db_detach(&db);
1103135446Strhodes	if (zone != NULL)
1104135446Strhodes		dns_zone_detach(&zone);
1105135446Strhodes
1106135446Strhodes	return (result);
1107135446Strhodes}
1108135446Strhodes
1109135446Strhodesisc_result_t
1110135446Strhodesdns_viewlist_find(dns_viewlist_t *list, const char *name,
1111135446Strhodes		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1112135446Strhodes{
1113135446Strhodes	dns_view_t *view;
1114135446Strhodes
1115135446Strhodes	REQUIRE(list != NULL);
1116135446Strhodes
1117135446Strhodes	for (view = ISC_LIST_HEAD(*list);
1118135446Strhodes	     view != NULL;
1119135446Strhodes	     view = ISC_LIST_NEXT(view, link)) {
1120135446Strhodes		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1121135446Strhodes			break;
1122135446Strhodes	}
1123135446Strhodes	if (view == NULL)
1124135446Strhodes		return (ISC_R_NOTFOUND);
1125135446Strhodes
1126135446Strhodes	dns_view_attach(view, viewp);
1127135446Strhodes
1128135446Strhodes	return (ISC_R_SUCCESS);
1129135446Strhodes}
1130135446Strhodes
1131135446Strhodesisc_result_t
1132135446Strhodesdns_view_load(dns_view_t *view, isc_boolean_t stop) {
1133135446Strhodes
1134135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1135135446Strhodes
1136135446Strhodes	return (dns_zt_load(view->zonetable, stop));
1137135446Strhodes}
1138135446Strhodes
1139135446Strhodesisc_result_t
1140135446Strhodesdns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1141135446Strhodes
1142135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1143135446Strhodes
1144135446Strhodes	return (dns_zt_loadnew(view->zonetable, stop));
1145135446Strhodes}
1146135446Strhodes
1147135446Strhodesisc_result_t
1148135446Strhodesdns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1149135446Strhodes{
1150135446Strhodes	isc_result_t result;
1151135446Strhodes	REQUIRE(keyp != NULL && *keyp == NULL);
1152135446Strhodes
1153135446Strhodes	result = dns_tsigkey_find(keyp, keyname, NULL,
1154135446Strhodes				  view->statickeys);
1155135446Strhodes	if (result == ISC_R_NOTFOUND)
1156135446Strhodes		result = dns_tsigkey_find(keyp, keyname, NULL,
1157135446Strhodes					  view->dynamickeys);
1158135446Strhodes	return (result);
1159135446Strhodes}
1160135446Strhodes
1161135446Strhodesisc_result_t
1162135446Strhodesdns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1163135446Strhodes		     dns_tsigkey_t **keyp)
1164135446Strhodes{
1165135446Strhodes	isc_result_t result;
1166135446Strhodes	dns_name_t *keyname = NULL;
1167135446Strhodes	dns_peer_t *peer = NULL;
1168135446Strhodes
1169135446Strhodes	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1170135446Strhodes	if (result != ISC_R_SUCCESS)
1171135446Strhodes		return (result);
1172135446Strhodes
1173135446Strhodes	result = dns_peer_getkey(peer, &keyname);
1174135446Strhodes	if (result != ISC_R_SUCCESS)
1175135446Strhodes		return (result);
1176135446Strhodes
1177135446Strhodes	return (dns_view_gettsig(view, keyname, keyp));
1178135446Strhodes}
1179135446Strhodes
1180135446Strhodesisc_result_t
1181135446Strhodesdns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1182135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1183135446Strhodes	REQUIRE(source != NULL);
1184135446Strhodes
1185135446Strhodes	return (dns_tsig_verify(source, msg, view->statickeys,
1186135446Strhodes				view->dynamickeys));
1187135446Strhodes}
1188135446Strhodes
1189135446Strhodesisc_result_t
1190135446Strhodesdns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1191135446Strhodes	isc_result_t result;
1192135446Strhodes
1193135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1194135446Strhodes
1195135446Strhodes	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1196135446Strhodes	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1197135446Strhodes					  &dns_master_style_cache, fp);
1198135446Strhodes	if (result != ISC_R_SUCCESS)
1199135446Strhodes		return (result);
1200135446Strhodes	dns_adb_dump(view->adb, fp);
1201135446Strhodes	return (ISC_R_SUCCESS);
1202135446Strhodes}
1203135446Strhodes
1204135446Strhodesisc_result_t
1205135446Strhodesdns_view_flushcache(dns_view_t *view) {
1206135446Strhodes	isc_result_t result;
1207135446Strhodes
1208135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1209135446Strhodes
1210135446Strhodes	if (view->cachedb == NULL)
1211135446Strhodes		return (ISC_R_SUCCESS);
1212135446Strhodes	result = dns_cache_flush(view->cache);
1213135446Strhodes	if (result != ISC_R_SUCCESS)
1214135446Strhodes		return (result);
1215170222Sdougb	if (view->acache != NULL)
1216170222Sdougb		dns_acache_putdb(view->acache, view->cachedb);
1217135446Strhodes	dns_db_detach(&view->cachedb);
1218135446Strhodes	dns_cache_attachdb(view->cache, &view->cachedb);
1219170222Sdougb	if (view->acache != NULL)
1220170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
1221135446Strhodes
1222135446Strhodes	dns_adb_flush(view->adb);
1223135446Strhodes	return (ISC_R_SUCCESS);
1224135446Strhodes}
1225135446Strhodes
1226135446Strhodesisc_result_t
1227135446Strhodesdns_view_flushname(dns_view_t *view, dns_name_t *name) {
1228135446Strhodes
1229135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1230135446Strhodes
1231135446Strhodes	if (view->adb != NULL)
1232135446Strhodes		dns_adb_flushname(view->adb, name);
1233135446Strhodes	if (view->cache == NULL)
1234135446Strhodes		return (ISC_R_SUCCESS);
1235135446Strhodes	return (dns_cache_flushname(view->cache, name));
1236135446Strhodes}
1237135446Strhodes
1238135446Strhodesisc_result_t
1239135446Strhodesdns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1240135446Strhodes	isc_result_t result;
1241135446Strhodes	dns_name_t *new;
1242135446Strhodes	isc_uint32_t hash;
1243135446Strhodes
1244135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1245135446Strhodes
1246135446Strhodes	if (view->delonly == NULL) {
1247135446Strhodes		view->delonly = isc_mem_get(view->mctx,
1248135446Strhodes					    sizeof(dns_namelist_t) *
1249135446Strhodes					    DNS_VIEW_DELONLYHASH);
1250135446Strhodes		if (view->delonly == NULL)
1251135446Strhodes			return (ISC_R_NOMEMORY);
1252135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1253135446Strhodes			ISC_LIST_INIT(view->delonly[hash]);
1254135446Strhodes	}
1255135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1256135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1257135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1258135446Strhodes		new = ISC_LIST_NEXT(new, link);
1259135446Strhodes	if (new != NULL)
1260135446Strhodes		return (ISC_R_SUCCESS);
1261135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1262135446Strhodes	if (new == NULL)
1263135446Strhodes		return (ISC_R_NOMEMORY);
1264135446Strhodes	dns_name_init(new, NULL);
1265135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1266135446Strhodes	if (result == ISC_R_SUCCESS)
1267135446Strhodes		ISC_LIST_APPEND(view->delonly[hash], new, link);
1268135446Strhodes	else
1269135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1270135446Strhodes	return (result);
1271135446Strhodes}
1272135446Strhodes
1273135446Strhodesisc_result_t
1274135446Strhodesdns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1275135446Strhodes	isc_result_t result;
1276135446Strhodes	dns_name_t *new;
1277135446Strhodes	isc_uint32_t hash;
1278135446Strhodes
1279135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1280135446Strhodes
1281135446Strhodes	if (view->rootexclude == NULL) {
1282135446Strhodes		view->rootexclude = isc_mem_get(view->mctx,
1283135446Strhodes					    sizeof(dns_namelist_t) *
1284135446Strhodes					    DNS_VIEW_DELONLYHASH);
1285135446Strhodes		if (view->rootexclude == NULL)
1286135446Strhodes			return (ISC_R_NOMEMORY);
1287135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1288135446Strhodes			ISC_LIST_INIT(view->rootexclude[hash]);
1289135446Strhodes	}
1290135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1291135446Strhodes	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1292135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1293135446Strhodes		new = ISC_LIST_NEXT(new, link);
1294135446Strhodes	if (new != NULL)
1295135446Strhodes		return (ISC_R_SUCCESS);
1296135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1297135446Strhodes	if (new == NULL)
1298135446Strhodes		return (ISC_R_NOMEMORY);
1299135446Strhodes	dns_name_init(new, NULL);
1300135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1301135446Strhodes	if (result == ISC_R_SUCCESS)
1302135446Strhodes		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1303135446Strhodes	else
1304135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1305135446Strhodes	return (result);
1306135446Strhodes}
1307135446Strhodes
1308135446Strhodesisc_boolean_t
1309135446Strhodesdns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1310135446Strhodes	dns_name_t *new;
1311135446Strhodes	isc_uint32_t hash;
1312135446Strhodes
1313135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1314135446Strhodes
1315135446Strhodes	if (!view->rootdelonly && view->delonly == NULL)
1316135446Strhodes		return (ISC_FALSE);
1317135446Strhodes
1318135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1319135446Strhodes	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1320135446Strhodes		if (view->rootexclude == NULL)
1321135446Strhodes			return (ISC_TRUE);
1322135446Strhodes		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1323135446Strhodes		while (new != NULL && !dns_name_equal(new, name))
1324135446Strhodes			new = ISC_LIST_NEXT(new, link);
1325135446Strhodes		if (new == NULL)
1326135446Strhodes			return (ISC_TRUE);
1327135446Strhodes	}
1328135446Strhodes
1329135446Strhodes	if (view->delonly == NULL)
1330135446Strhodes		return (ISC_FALSE);
1331135446Strhodes
1332135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1333135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1334135446Strhodes		new = ISC_LIST_NEXT(new, link);
1335135446Strhodes	if (new == NULL)
1336135446Strhodes		return (ISC_FALSE);
1337135446Strhodes	return (ISC_TRUE);
1338135446Strhodes}
1339135446Strhodes
1340186462Sdougbvoid
1341135446Strhodesdns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1342135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1343135446Strhodes	view->rootdelonly = value;
1344135446Strhodes}
1345135446Strhodes
1346135446Strhodesisc_boolean_t
1347135446Strhodesdns_view_getrootdelonly(dns_view_t *view) {
1348135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1349135446Strhodes	return (view->rootdelonly);
1350135446Strhodes}
1351170222Sdougb
1352170222Sdougbisc_result_t
1353170222Sdougbdns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1354170222Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1355170222Sdougb	return (dns_zt_freezezones(view->zonetable, value));
1356170222Sdougb}
1357