1135446Strhodes/*
2254402Serwin * Copyright (C) 2004-2013  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
18234010Sdougb/* $Id$ */
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>
38254897Serwin#include <dns/dispatch.h>
39170222Sdougb#include <dns/dlz.h>
40224092Sdougb#ifdef BIND9
41224092Sdougb#include <dns/dns64.h>
42224092Sdougb#endif
43224092Sdougb#include <dns/dnssec.h>
44135446Strhodes#include <dns/events.h>
45135446Strhodes#include <dns/forward.h>
46135446Strhodes#include <dns/keytable.h>
47224092Sdougb#include <dns/keyvalues.h>
48135446Strhodes#include <dns/master.h>
49135446Strhodes#include <dns/masterdump.h>
50135446Strhodes#include <dns/order.h>
51135446Strhodes#include <dns/peer.h>
52262706Serwin#include <dns/rrl.h>
53224092Sdougb#include <dns/rbt.h>
54135446Strhodes#include <dns/rdataset.h>
55135446Strhodes#include <dns/request.h>
56135446Strhodes#include <dns/resolver.h>
57135446Strhodes#include <dns/result.h>
58224092Sdougb#include <dns/rpz.h>
59193149Sdougb#include <dns/stats.h>
60135446Strhodes#include <dns/tsig.h>
61135446Strhodes#include <dns/zone.h>
62135446Strhodes#include <dns/zt.h>
63135446Strhodes
64135446Strhodes#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
65135446Strhodes#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
66135446Strhodes#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
67135446Strhodes
68135446Strhodes#define DNS_VIEW_DELONLYHASH 111
69135446Strhodes
70135446Strhodesstatic void resolver_shutdown(isc_task_t *task, isc_event_t *event);
71135446Strhodesstatic void adb_shutdown(isc_task_t *task, isc_event_t *event);
72135446Strhodesstatic void req_shutdown(isc_task_t *task, isc_event_t *event);
73135446Strhodes
74135446Strhodesisc_result_t
75135446Strhodesdns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
76135446Strhodes		const char *name, dns_view_t **viewp)
77135446Strhodes{
78135446Strhodes	dns_view_t *view;
79135446Strhodes	isc_result_t result;
80135446Strhodes
81135446Strhodes	/*
82135446Strhodes	 * Create a view.
83135446Strhodes	 */
84135446Strhodes
85135446Strhodes	REQUIRE(name != NULL);
86135446Strhodes	REQUIRE(viewp != NULL && *viewp == NULL);
87135446Strhodes
88135446Strhodes	view = isc_mem_get(mctx, sizeof(*view));
89135446Strhodes	if (view == NULL)
90135446Strhodes		return (ISC_R_NOMEMORY);
91254402Serwin
92254402Serwin	view->mctx = NULL;
93254402Serwin	isc_mem_attach(mctx, &view->mctx);
94135446Strhodes	view->name = isc_mem_strdup(mctx, name);
95135446Strhodes	if (view->name == NULL) {
96135446Strhodes		result = ISC_R_NOMEMORY;
97135446Strhodes		goto cleanup_view;
98135446Strhodes	}
99135446Strhodes	result = isc_mutex_init(&view->lock);
100170222Sdougb	if (result != ISC_R_SUCCESS)
101135446Strhodes		goto cleanup_name;
102170222Sdougb
103254402Serwin	view->zonetable = NULL;
104224092Sdougb#ifdef BIND9
105135446Strhodes	result = dns_zt_create(mctx, rdclass, &view->zonetable);
106135446Strhodes	if (result != ISC_R_SUCCESS) {
107135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
108135446Strhodes				 "dns_zt_create() failed: %s",
109135446Strhodes				 isc_result_totext(result));
110135446Strhodes		result = ISC_R_UNEXPECTED;
111135446Strhodes		goto cleanup_mutex;
112135446Strhodes	}
113224092Sdougb#endif
114224092Sdougb	view->secroots_priv = NULL;
115135446Strhodes	view->fwdtable = NULL;
116135446Strhodes	result = dns_fwdtable_create(mctx, &view->fwdtable);
117135446Strhodes	if (result != ISC_R_SUCCESS) {
118135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
119135446Strhodes				 "dns_fwdtable_create() failed: %s",
120135446Strhodes				 isc_result_totext(result));
121135446Strhodes		result = ISC_R_UNEXPECTED;
122224092Sdougb		goto cleanup_zt;
123135446Strhodes	}
124135446Strhodes
125170222Sdougb	view->acache = NULL;
126135446Strhodes	view->cache = NULL;
127135446Strhodes	view->cachedb = NULL;
128170222Sdougb	view->dlzdatabase = NULL;
129135446Strhodes	view->hints = NULL;
130135446Strhodes	view->resolver = NULL;
131135446Strhodes	view->adb = NULL;
132135446Strhodes	view->requestmgr = NULL;
133135446Strhodes	view->rdclass = rdclass;
134135446Strhodes	view->frozen = ISC_FALSE;
135135446Strhodes	view->task = NULL;
136170222Sdougb	result = isc_refcount_init(&view->references, 1);
137170222Sdougb	if (result != ISC_R_SUCCESS)
138170222Sdougb		goto cleanup_fwdtable;
139135446Strhodes	view->weakrefs = 0;
140135446Strhodes	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
141135446Strhodes			    DNS_VIEWATTR_REQSHUTDOWN);
142135446Strhodes	view->statickeys = NULL;
143135446Strhodes	view->dynamickeys = NULL;
144135446Strhodes	view->matchclients = NULL;
145135446Strhodes	view->matchdestinations = NULL;
146135446Strhodes	view->matchrecursiveonly = ISC_FALSE;
147135446Strhodes	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
148135446Strhodes	if (result != ISC_R_SUCCESS)
149170222Sdougb		goto cleanup_references;
150135446Strhodes	view->peers = NULL;
151135446Strhodes	view->order = NULL;
152135446Strhodes	view->delonly = NULL;
153135446Strhodes	view->rootdelonly = ISC_FALSE;
154135446Strhodes	view->rootexclude = NULL;
155193149Sdougb	view->resstats = NULL;
156193149Sdougb	view->resquerystats = NULL;
157224092Sdougb	view->cacheshared = ISC_FALSE;
158224092Sdougb	ISC_LIST_INIT(view->dns64);
159224092Sdougb	view->dns64cnt = 0;
160135446Strhodes
161135446Strhodes	/*
162135446Strhodes	 * Initialize configuration data with default values.
163135446Strhodes	 */
164135446Strhodes	view->recursion = ISC_TRUE;
165135446Strhodes	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
166135446Strhodes	view->additionalfromcache = ISC_TRUE;
167135446Strhodes	view->additionalfromauth = ISC_TRUE;
168135446Strhodes	view->enablednssec = ISC_TRUE;
169170222Sdougb	view->enablevalidation = ISC_TRUE;
170170222Sdougb	view->acceptexpired = ISC_FALSE;
171135446Strhodes	view->minimalresponses = ISC_FALSE;
172135446Strhodes	view->transfer_format = dns_one_answer;
173216175Sdougb	view->cacheacl = NULL;
174216175Sdougb	view->cacheonacl = NULL;
175135446Strhodes	view->queryacl = NULL;
176193149Sdougb	view->queryonacl = NULL;
177135446Strhodes	view->recursionacl = NULL;
178193149Sdougb	view->recursiononacl = NULL;
179135446Strhodes	view->sortlist = NULL;
180193149Sdougb	view->transferacl = NULL;
181193149Sdougb	view->notifyacl = NULL;
182193149Sdougb	view->updateacl = NULL;
183193149Sdougb	view->upfwdacl = NULL;
184224092Sdougb	view->denyansweracl = NULL;
185224092Sdougb	view->answeracl_exclude = NULL;
186224092Sdougb	view->denyanswernames = NULL;
187224092Sdougb	view->answernames_exclude = NULL;
188262706Serwin	view->rrl = NULL;
189135446Strhodes	view->provideixfr = ISC_TRUE;
190135446Strhodes	view->maxcachettl = 7 * 24 * 3600;
191135446Strhodes	view->maxncachettl = 3 * 3600;
192135446Strhodes	view->dstport = 53;
193135446Strhodes	view->preferred_glue = 0;
194135446Strhodes	view->flush = ISC_FALSE;
195135446Strhodes	view->dlv = NULL;
196170222Sdougb	view->maxudp = 0;
197254897Serwin	view->maxbits = 0;
198224092Sdougb	view->v4_aaaa = dns_v4_aaaa_ok;
199224092Sdougb	view->v4_aaaa_acl = NULL;
200224092Sdougb	ISC_LIST_INIT(view->rpz_zones);
201245163Serwin	view->rpz_recursive_only = ISC_TRUE;
202245163Serwin	view->rpz_break_dnssec = ISC_FALSE;
203135446Strhodes	dns_fixedname_init(&view->dlv_fixed);
204224092Sdougb	view->managed_keys = NULL;
205254897Serwin	view->redirect = NULL;
206224092Sdougb#ifdef BIND9
207224092Sdougb	view->new_zone_file = NULL;
208224092Sdougb	view->new_zone_config = NULL;
209224092Sdougb	view->cfg_destroy = NULL;
210135446Strhodes
211135446Strhodes	result = dns_order_create(view->mctx, &view->order);
212135446Strhodes	if (result != ISC_R_SUCCESS)
213135446Strhodes		goto cleanup_dynkeys;
214224092Sdougb#endif
215135446Strhodes
216135446Strhodes	result = dns_peerlist_new(view->mctx, &view->peers);
217135446Strhodes	if (result != ISC_R_SUCCESS)
218135446Strhodes		goto cleanup_order;
219135446Strhodes
220135446Strhodes	result = dns_aclenv_init(view->mctx, &view->aclenv);
221135446Strhodes	if (result != ISC_R_SUCCESS)
222135446Strhodes		goto cleanup_peerlist;
223135446Strhodes
224135446Strhodes	ISC_LINK_INIT(view, link);
225135446Strhodes	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
226135446Strhodes		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
227135446Strhodes		       view, NULL, NULL, NULL);
228135446Strhodes	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
229135446Strhodes		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
230135446Strhodes		       view, NULL, NULL, NULL);
231135446Strhodes	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
232135446Strhodes		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
233135446Strhodes		       view, NULL, NULL, NULL);
234254402Serwin	view->viewlist = NULL;
235135446Strhodes	view->magic = DNS_VIEW_MAGIC;
236135446Strhodes
237135446Strhodes	*viewp = view;
238135446Strhodes
239135446Strhodes	return (ISC_R_SUCCESS);
240135446Strhodes
241135446Strhodes cleanup_peerlist:
242135446Strhodes	dns_peerlist_detach(&view->peers);
243135446Strhodes
244135446Strhodes cleanup_order:
245224092Sdougb#ifdef BIND9
246135446Strhodes	dns_order_detach(&view->order);
247135446Strhodes
248135446Strhodes cleanup_dynkeys:
249224092Sdougb#endif
250224092Sdougb	dns_tsigkeyring_detach(&view->dynamickeys);
251135446Strhodes
252170222Sdougb cleanup_references:
253170222Sdougb	isc_refcount_destroy(&view->references);
254170222Sdougb
255135446Strhodes cleanup_fwdtable:
256135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
257135446Strhodes
258135446Strhodes cleanup_zt:
259224092Sdougb#ifdef BIND9
260135446Strhodes	dns_zt_detach(&view->zonetable);
261135446Strhodes
262135446Strhodes cleanup_mutex:
263224092Sdougb#endif
264135446Strhodes	DESTROYLOCK(&view->lock);
265135446Strhodes
266135446Strhodes cleanup_name:
267135446Strhodes	isc_mem_free(mctx, view->name);
268135446Strhodes
269135446Strhodes cleanup_view:
270254402Serwin	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
271135446Strhodes
272135446Strhodes	return (result);
273135446Strhodes}
274135446Strhodes
275135446Strhodesstatic inline void
276135446Strhodesdestroy(dns_view_t *view) {
277224092Sdougb#ifdef BIND9
278224092Sdougb	dns_dns64_t *dns64;
279224092Sdougb#endif
280224092Sdougb
281135446Strhodes	REQUIRE(!ISC_LINK_LINKED(view, link));
282135446Strhodes	REQUIRE(isc_refcount_current(&view->references) == 0);
283135446Strhodes	REQUIRE(view->weakrefs == 0);
284135446Strhodes	REQUIRE(RESSHUTDOWN(view));
285135446Strhodes	REQUIRE(ADBSHUTDOWN(view));
286135446Strhodes	REQUIRE(REQSHUTDOWN(view));
287135446Strhodes
288224092Sdougb#ifdef BIND9
289135446Strhodes	if (view->order != NULL)
290135446Strhodes		dns_order_detach(&view->order);
291224092Sdougb#endif
292135446Strhodes	if (view->peers != NULL)
293135446Strhodes		dns_peerlist_detach(&view->peers);
294224092Sdougb
295224092Sdougb	if (view->dynamickeys != NULL) {
296224092Sdougb		isc_result_t result;
297224092Sdougb		char template[20];
298224092Sdougb		char keyfile[20];
299224092Sdougb		FILE *fp = NULL;
300224092Sdougb		int n;
301224092Sdougb
302224092Sdougb		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
303224092Sdougb			     view->name);
304224092Sdougb		if (n > 0 && (size_t)n < sizeof(keyfile)) {
305224092Sdougb			result = isc_file_mktemplate(keyfile, template,
306224092Sdougb						     sizeof(template));
307224092Sdougb			if (result == ISC_R_SUCCESS)
308224092Sdougb				(void)isc_file_openuniqueprivate(template, &fp);
309224092Sdougb		}
310224092Sdougb		if (fp == NULL)
311224092Sdougb			dns_tsigkeyring_detach(&view->dynamickeys);
312224092Sdougb		else {
313224092Sdougb			result = dns_tsigkeyring_dumpanddetach(
314224092Sdougb							&view->dynamickeys, fp);
315224092Sdougb			if (result == ISC_R_SUCCESS) {
316224092Sdougb				if (fclose(fp) == 0)
317224092Sdougb					result = isc_file_rename(template,
318224092Sdougb								 keyfile);
319224092Sdougb				if (result != ISC_R_SUCCESS)
320224092Sdougb					(void)remove(template);
321224092Sdougb			} else {
322224092Sdougb				(void)fclose(fp);
323224092Sdougb				(void)remove(template);
324224092Sdougb			}
325224092Sdougb		}
326224092Sdougb	}
327135446Strhodes	if (view->statickeys != NULL)
328224092Sdougb		dns_tsigkeyring_detach(&view->statickeys);
329135446Strhodes	if (view->adb != NULL)
330135446Strhodes		dns_adb_detach(&view->adb);
331135446Strhodes	if (view->resolver != NULL)
332135446Strhodes		dns_resolver_detach(&view->resolver);
333224092Sdougb#ifdef BIND9
334170222Sdougb	if (view->acache != NULL) {
335170222Sdougb		if (view->cachedb != NULL)
336170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
337170222Sdougb		dns_acache_detach(&view->acache);
338170222Sdougb	}
339224092Sdougb	dns_rpz_view_destroy(view);
340262706Serwin#ifdef USE_RRL
341262706Serwin	dns_rrl_view_destroy(view);
342262706Serwin#else /* USE_RRL */
343262706Serwin	INSIST(view->rrl == NULL);
344262706Serwin#endif /* USE_RRL */
345262706Serwin#else /* BIND9 */
346224092Sdougb	INSIST(view->acache == NULL);
347224092Sdougb	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
348262706Serwin	INSIST(view->rrl == NULL);
349262706Serwin#endif /* BIND9 */
350135446Strhodes	if (view->requestmgr != NULL)
351135446Strhodes		dns_requestmgr_detach(&view->requestmgr);
352135446Strhodes	if (view->task != NULL)
353135446Strhodes		isc_task_detach(&view->task);
354135446Strhodes	if (view->hints != NULL)
355135446Strhodes		dns_db_detach(&view->hints);
356170222Sdougb	if (view->dlzdatabase != NULL)
357170222Sdougb		dns_dlzdestroy(&view->dlzdatabase);
358135446Strhodes	if (view->cachedb != NULL)
359135446Strhodes		dns_db_detach(&view->cachedb);
360135446Strhodes	if (view->cache != NULL)
361135446Strhodes		dns_cache_detach(&view->cache);
362135446Strhodes	if (view->matchclients != NULL)
363135446Strhodes		dns_acl_detach(&view->matchclients);
364135446Strhodes	if (view->matchdestinations != NULL)
365135446Strhodes		dns_acl_detach(&view->matchdestinations);
366216175Sdougb	if (view->cacheacl != NULL)
367216175Sdougb		dns_acl_detach(&view->cacheacl);
368216175Sdougb	if (view->cacheonacl != NULL)
369216175Sdougb		dns_acl_detach(&view->cacheonacl);
370135446Strhodes	if (view->queryacl != NULL)
371135446Strhodes		dns_acl_detach(&view->queryacl);
372193149Sdougb	if (view->queryonacl != NULL)
373193149Sdougb		dns_acl_detach(&view->queryonacl);
374135446Strhodes	if (view->recursionacl != NULL)
375135446Strhodes		dns_acl_detach(&view->recursionacl);
376193149Sdougb	if (view->recursiononacl != NULL)
377193149Sdougb		dns_acl_detach(&view->recursiononacl);
378135446Strhodes	if (view->sortlist != NULL)
379135446Strhodes		dns_acl_detach(&view->sortlist);
380193149Sdougb	if (view->transferacl != NULL)
381193149Sdougb		dns_acl_detach(&view->transferacl);
382193149Sdougb	if (view->notifyacl != NULL)
383193149Sdougb		dns_acl_detach(&view->notifyacl);
384193149Sdougb	if (view->updateacl != NULL)
385193149Sdougb		dns_acl_detach(&view->updateacl);
386193149Sdougb	if (view->upfwdacl != NULL)
387193149Sdougb		dns_acl_detach(&view->upfwdacl);
388224092Sdougb	if (view->denyansweracl != NULL)
389224092Sdougb		dns_acl_detach(&view->denyansweracl);
390224092Sdougb	if (view->v4_aaaa_acl != NULL)
391224092Sdougb		dns_acl_detach(&view->v4_aaaa_acl);
392224092Sdougb	if (view->answeracl_exclude != NULL)
393224092Sdougb		dns_rbt_destroy(&view->answeracl_exclude);
394224092Sdougb	if (view->denyanswernames != NULL)
395224092Sdougb		dns_rbt_destroy(&view->denyanswernames);
396224092Sdougb	if (view->answernames_exclude != NULL)
397224092Sdougb		dns_rbt_destroy(&view->answernames_exclude);
398135446Strhodes	if (view->delonly != NULL) {
399135446Strhodes		dns_name_t *name;
400135446Strhodes		int i;
401135446Strhodes
402135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
403135446Strhodes			name = ISC_LIST_HEAD(view->delonly[i]);
404135446Strhodes			while (name != NULL) {
405135446Strhodes				ISC_LIST_UNLINK(view->delonly[i], name, link);
406135446Strhodes				dns_name_free(name, view->mctx);
407135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
408135446Strhodes				name = ISC_LIST_HEAD(view->delonly[i]);
409135446Strhodes			}
410135446Strhodes		}
411135446Strhodes		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
412135446Strhodes			    DNS_VIEW_DELONLYHASH);
413135446Strhodes		view->delonly = NULL;
414135446Strhodes	}
415135446Strhodes	if (view->rootexclude != NULL) {
416135446Strhodes		dns_name_t *name;
417135446Strhodes		int i;
418135446Strhodes
419135446Strhodes		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
420135446Strhodes			name = ISC_LIST_HEAD(view->rootexclude[i]);
421135446Strhodes			while (name != NULL) {
422135446Strhodes				ISC_LIST_UNLINK(view->rootexclude[i],
423186462Sdougb						name, link);
424135446Strhodes				dns_name_free(name, view->mctx);
425135446Strhodes				isc_mem_put(view->mctx, name, sizeof(*name));
426135446Strhodes				name = ISC_LIST_HEAD(view->rootexclude[i]);
427135446Strhodes			}
428135446Strhodes		}
429135446Strhodes		isc_mem_put(view->mctx, view->rootexclude,
430135446Strhodes			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
431135446Strhodes		view->rootexclude = NULL;
432135446Strhodes	}
433193149Sdougb	if (view->resstats != NULL)
434193149Sdougb		isc_stats_detach(&view->resstats);
435193149Sdougb	if (view->resquerystats != NULL)
436193149Sdougb		dns_stats_detach(&view->resquerystats);
437224092Sdougb	if (view->secroots_priv != NULL)
438224092Sdougb		dns_keytable_detach(&view->secroots_priv);
439224092Sdougb#ifdef BIND9
440224092Sdougb	for (dns64 = ISC_LIST_HEAD(view->dns64);
441224092Sdougb	     dns64 != NULL;
442224092Sdougb	     dns64 = ISC_LIST_HEAD(view->dns64)) {
443224092Sdougb		dns_dns64_unlink(&view->dns64, dns64);
444224092Sdougb		dns_dns64_destroy(&dns64);
445224092Sdougb	}
446224092Sdougb	if (view->managed_keys != NULL)
447224092Sdougb		dns_zone_detach(&view->managed_keys);
448254897Serwin	if (view->redirect != NULL)
449254897Serwin		dns_zone_detach(&view->redirect);
450224092Sdougb	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
451224092Sdougb#endif
452135446Strhodes	dns_fwdtable_destroy(&view->fwdtable);
453135446Strhodes	dns_aclenv_destroy(&view->aclenv);
454135446Strhodes	DESTROYLOCK(&view->lock);
455135446Strhodes	isc_refcount_destroy(&view->references);
456135446Strhodes	isc_mem_free(view->mctx, view->name);
457254402Serwin	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
458135446Strhodes}
459135446Strhodes
460135446Strhodes/*
461135446Strhodes * Return true iff 'view' may be freed.
462135446Strhodes * The caller must be holding the view lock.
463135446Strhodes */
464135446Strhodesstatic isc_boolean_t
465135446Strhodesall_done(dns_view_t *view) {
466135446Strhodes
467135446Strhodes	if (isc_refcount_current(&view->references) == 0 &&
468135446Strhodes	    view->weakrefs == 0 &&
469135446Strhodes	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
470135446Strhodes		return (ISC_TRUE);
471135446Strhodes
472135446Strhodes	return (ISC_FALSE);
473135446Strhodes}
474135446Strhodes
475135446Strhodesvoid
476135446Strhodesdns_view_attach(dns_view_t *source, dns_view_t **targetp) {
477135446Strhodes
478135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
479135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
480135446Strhodes
481135446Strhodes	isc_refcount_increment(&source->references, NULL);
482135446Strhodes
483135446Strhodes	*targetp = source;
484135446Strhodes}
485135446Strhodes
486135446Strhodesstatic void
487135446Strhodesview_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
488135446Strhodes	dns_view_t *view;
489135446Strhodes	unsigned int refs;
490135446Strhodes	isc_boolean_t done = ISC_FALSE;
491135446Strhodes
492135446Strhodes	REQUIRE(viewp != NULL);
493135446Strhodes	view = *viewp;
494135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
495135446Strhodes
496135446Strhodes	if (flush)
497135446Strhodes		view->flush = ISC_TRUE;
498135446Strhodes	isc_refcount_decrement(&view->references, &refs);
499135446Strhodes	if (refs == 0) {
500254402Serwin#ifdef BIND9
501254897Serwin		dns_zone_t *mkzone = NULL, *rdzone = NULL;
502254402Serwin#endif
503254402Serwin
504135446Strhodes		LOCK(&view->lock);
505135446Strhodes		if (!RESSHUTDOWN(view))
506135446Strhodes			dns_resolver_shutdown(view->resolver);
507135446Strhodes		if (!ADBSHUTDOWN(view))
508135446Strhodes			dns_adb_shutdown(view->adb);
509135446Strhodes		if (!REQSHUTDOWN(view))
510135446Strhodes			dns_requestmgr_shutdown(view->requestmgr);
511224092Sdougb#ifdef BIND9
512170222Sdougb		if (view->acache != NULL)
513170222Sdougb			dns_acache_shutdown(view->acache);
514135446Strhodes		if (view->flush)
515135446Strhodes			dns_zt_flushanddetach(&view->zonetable);
516135446Strhodes		else
517135446Strhodes			dns_zt_detach(&view->zonetable);
518224092Sdougb		if (view->managed_keys != NULL) {
519254402Serwin			mkzone = view->managed_keys;
520254402Serwin			view->managed_keys = NULL;
521224092Sdougb			if (view->flush)
522254402Serwin				dns_zone_flush(mkzone);
523224092Sdougb		}
524254897Serwin		if (view->redirect != NULL) {
525254897Serwin			rdzone = view->redirect;
526254897Serwin			view->redirect = NULL;
527254897Serwin			if (view->flush)
528254897Serwin				dns_zone_flush(rdzone);
529254897Serwin		}
530224092Sdougb#endif
531135446Strhodes		done = all_done(view);
532135446Strhodes		UNLOCK(&view->lock);
533254402Serwin
534254402Serwin#ifdef BIND9
535254402Serwin		/* Need to detach zones outside view lock */
536254402Serwin		if (mkzone != NULL)
537254402Serwin			dns_zone_detach(&mkzone);
538254897Serwin
539254897Serwin		if (rdzone != NULL)
540254897Serwin			dns_zone_detach(&rdzone);
541254402Serwin#endif
542135446Strhodes	}
543135446Strhodes
544135446Strhodes	*viewp = NULL;
545135446Strhodes
546135446Strhodes	if (done)
547135446Strhodes		destroy(view);
548135446Strhodes}
549135446Strhodes
550135446Strhodesvoid
551135446Strhodesdns_view_flushanddetach(dns_view_t **viewp) {
552135446Strhodes	view_flushanddetach(viewp, ISC_TRUE);
553135446Strhodes}
554135446Strhodes
555135446Strhodesvoid
556135446Strhodesdns_view_detach(dns_view_t **viewp) {
557135446Strhodes	view_flushanddetach(viewp, ISC_FALSE);
558135446Strhodes}
559135446Strhodes
560224092Sdougb#ifdef BIND9
561135446Strhodesstatic isc_result_t
562135446Strhodesdialup(dns_zone_t *zone, void *dummy) {
563135446Strhodes	UNUSED(dummy);
564135446Strhodes	dns_zone_dialup(zone);
565135446Strhodes	return (ISC_R_SUCCESS);
566135446Strhodes}
567135446Strhodes
568135446Strhodesvoid
569135446Strhodesdns_view_dialup(dns_view_t *view) {
570135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
571262706Serwin	REQUIRE(view->zonetable != NULL);
572262706Serwin
573135446Strhodes	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
574135446Strhodes}
575224092Sdougb#endif
576135446Strhodes
577135446Strhodesvoid
578135446Strhodesdns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
579135446Strhodes
580135446Strhodes	REQUIRE(DNS_VIEW_VALID(source));
581135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
582135446Strhodes
583135446Strhodes	LOCK(&source->lock);
584135446Strhodes	source->weakrefs++;
585135446Strhodes	UNLOCK(&source->lock);
586135446Strhodes
587135446Strhodes	*targetp = source;
588135446Strhodes}
589135446Strhodes
590135446Strhodesvoid
591135446Strhodesdns_view_weakdetach(dns_view_t **viewp) {
592135446Strhodes	dns_view_t *view;
593135446Strhodes	isc_boolean_t done = ISC_FALSE;
594135446Strhodes
595135446Strhodes	REQUIRE(viewp != NULL);
596135446Strhodes	view = *viewp;
597135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
598135446Strhodes
599135446Strhodes	LOCK(&view->lock);
600135446Strhodes
601135446Strhodes	INSIST(view->weakrefs > 0);
602135446Strhodes	view->weakrefs--;
603135446Strhodes	done = all_done(view);
604135446Strhodes
605135446Strhodes	UNLOCK(&view->lock);
606135446Strhodes
607135446Strhodes	*viewp = NULL;
608135446Strhodes
609135446Strhodes	if (done)
610135446Strhodes		destroy(view);
611135446Strhodes}
612135446Strhodes
613135446Strhodesstatic void
614135446Strhodesresolver_shutdown(isc_task_t *task, isc_event_t *event) {
615135446Strhodes	dns_view_t *view = event->ev_arg;
616135446Strhodes	isc_boolean_t done;
617135446Strhodes
618135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
619135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
620135446Strhodes	REQUIRE(view->task == task);
621135446Strhodes
622135446Strhodes	UNUSED(task);
623135446Strhodes
624135446Strhodes	LOCK(&view->lock);
625135446Strhodes
626135446Strhodes	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
627135446Strhodes	done = all_done(view);
628135446Strhodes
629135446Strhodes	UNLOCK(&view->lock);
630135446Strhodes
631135446Strhodes	isc_event_free(&event);
632135446Strhodes
633135446Strhodes	if (done)
634135446Strhodes		destroy(view);
635135446Strhodes}
636135446Strhodes
637135446Strhodesstatic void
638135446Strhodesadb_shutdown(isc_task_t *task, isc_event_t *event) {
639135446Strhodes	dns_view_t *view = event->ev_arg;
640135446Strhodes	isc_boolean_t done;
641135446Strhodes
642135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
643135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
644135446Strhodes	REQUIRE(view->task == task);
645135446Strhodes
646135446Strhodes	UNUSED(task);
647135446Strhodes
648135446Strhodes	LOCK(&view->lock);
649135446Strhodes
650135446Strhodes	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
651135446Strhodes	done = all_done(view);
652135446Strhodes
653135446Strhodes	UNLOCK(&view->lock);
654135446Strhodes
655135446Strhodes	isc_event_free(&event);
656135446Strhodes
657135446Strhodes	if (done)
658135446Strhodes		destroy(view);
659135446Strhodes}
660135446Strhodes
661135446Strhodesstatic void
662135446Strhodesreq_shutdown(isc_task_t *task, isc_event_t *event) {
663135446Strhodes	dns_view_t *view = event->ev_arg;
664135446Strhodes	isc_boolean_t done;
665135446Strhodes
666135446Strhodes	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
667135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
668135446Strhodes	REQUIRE(view->task == task);
669135446Strhodes
670135446Strhodes	UNUSED(task);
671135446Strhodes
672135446Strhodes	LOCK(&view->lock);
673135446Strhodes
674135446Strhodes	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
675135446Strhodes	done = all_done(view);
676135446Strhodes
677135446Strhodes	UNLOCK(&view->lock);
678135446Strhodes
679135446Strhodes	isc_event_free(&event);
680135446Strhodes
681135446Strhodes	if (done)
682135446Strhodes		destroy(view);
683135446Strhodes}
684135446Strhodes
685135446Strhodesisc_result_t
686135446Strhodesdns_view_createresolver(dns_view_t *view,
687254897Serwin			isc_taskmgr_t *taskmgr,
688254897Serwin			unsigned int ntasks, unsigned int ndisp,
689135446Strhodes			isc_socketmgr_t *socketmgr,
690135446Strhodes			isc_timermgr_t *timermgr,
691135446Strhodes			unsigned int options,
692135446Strhodes			dns_dispatchmgr_t *dispatchmgr,
693135446Strhodes			dns_dispatch_t *dispatchv4,
694135446Strhodes			dns_dispatch_t *dispatchv6)
695135446Strhodes{
696135446Strhodes	isc_result_t result;
697135446Strhodes	isc_event_t *event;
698135446Strhodes	isc_mem_t *mctx = NULL;
699135446Strhodes
700135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
701135446Strhodes	REQUIRE(!view->frozen);
702135446Strhodes	REQUIRE(view->resolver == NULL);
703135446Strhodes
704135446Strhodes	result = isc_task_create(taskmgr, 0, &view->task);
705135446Strhodes	if (result != ISC_R_SUCCESS)
706135446Strhodes		return (result);
707135446Strhodes	isc_task_setname(view->task, "view", view);
708135446Strhodes
709254897Serwin	result = dns_resolver_create(view, taskmgr, ntasks, ndisp, socketmgr,
710135446Strhodes				     timermgr, options, dispatchmgr,
711135446Strhodes				     dispatchv4, dispatchv6,
712135446Strhodes				     &view->resolver);
713135446Strhodes	if (result != ISC_R_SUCCESS) {
714135446Strhodes		isc_task_detach(&view->task);
715135446Strhodes		return (result);
716135446Strhodes	}
717135446Strhodes	event = &view->resevent;
718135446Strhodes	dns_resolver_whenshutdown(view->resolver, view->task, &event);
719135446Strhodes	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
720135446Strhodes
721135446Strhodes	result = isc_mem_create(0, 0, &mctx);
722135446Strhodes	if (result != ISC_R_SUCCESS) {
723135446Strhodes		dns_resolver_shutdown(view->resolver);
724135446Strhodes		return (result);
725135446Strhodes	}
726135446Strhodes
727135446Strhodes	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
728193149Sdougb	isc_mem_setname(mctx, "ADB", NULL);
729135446Strhodes	isc_mem_detach(&mctx);
730135446Strhodes	if (result != ISC_R_SUCCESS) {
731135446Strhodes		dns_resolver_shutdown(view->resolver);
732135446Strhodes		return (result);
733135446Strhodes	}
734135446Strhodes	event = &view->adbevent;
735135446Strhodes	dns_adb_whenshutdown(view->adb, view->task, &event);
736135446Strhodes	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
737135446Strhodes
738135446Strhodes	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
739135446Strhodes				      dns_resolver_taskmgr(view->resolver),
740135446Strhodes				      dns_resolver_dispatchmgr(view->resolver),
741254897Serwin				      dispatchv4, dispatchv6,
742135446Strhodes				      &view->requestmgr);
743135446Strhodes	if (result != ISC_R_SUCCESS) {
744135446Strhodes		dns_adb_shutdown(view->adb);
745135446Strhodes		dns_resolver_shutdown(view->resolver);
746135446Strhodes		return (result);
747135446Strhodes	}
748135446Strhodes	event = &view->reqevent;
749135446Strhodes	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
750135446Strhodes	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
751135446Strhodes
752135446Strhodes	return (ISC_R_SUCCESS);
753135446Strhodes}
754135446Strhodes
755135446Strhodesvoid
756135446Strhodesdns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
757224092Sdougb	dns_view_setcache2(view, cache, ISC_FALSE);
758224092Sdougb}
759224092Sdougb
760224092Sdougbvoid
761224092Sdougbdns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
762135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
763135446Strhodes	REQUIRE(!view->frozen);
764135446Strhodes
765224092Sdougb	view->cacheshared = shared;
766135446Strhodes	if (view->cache != NULL) {
767224092Sdougb#ifdef BIND9
768170222Sdougb		if (view->acache != NULL)
769170222Sdougb			dns_acache_putdb(view->acache, view->cachedb);
770224092Sdougb#endif
771135446Strhodes		dns_db_detach(&view->cachedb);
772135446Strhodes		dns_cache_detach(&view->cache);
773135446Strhodes	}
774135446Strhodes	dns_cache_attach(cache, &view->cache);
775135446Strhodes	dns_cache_attachdb(cache, &view->cachedb);
776135446Strhodes	INSIST(DNS_DB_VALID(view->cachedb));
777170222Sdougb
778224092Sdougb#ifdef BIND9
779170222Sdougb	if (view->acache != NULL)
780170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
781224092Sdougb#endif
782135446Strhodes}
783135446Strhodes
784224092Sdougbisc_boolean_t
785224092Sdougbdns_view_iscacheshared(dns_view_t *view) {
786224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
787224092Sdougb
788224092Sdougb	return (view->cacheshared);
789224092Sdougb}
790224092Sdougb
791135446Strhodesvoid
792135446Strhodesdns_view_sethints(dns_view_t *view, dns_db_t *hints) {
793135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
794135446Strhodes	REQUIRE(!view->frozen);
795135446Strhodes	REQUIRE(view->hints == NULL);
796135446Strhodes	REQUIRE(dns_db_iszone(hints));
797135446Strhodes
798135446Strhodes	dns_db_attach(hints, &view->hints);
799135446Strhodes}
800135446Strhodes
801135446Strhodesvoid
802135446Strhodesdns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
803135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
804135446Strhodes	REQUIRE(ring != NULL);
805135446Strhodes	if (view->statickeys != NULL)
806224092Sdougb		dns_tsigkeyring_detach(&view->statickeys);
807224092Sdougb	dns_tsigkeyring_attach(ring, &view->statickeys);
808135446Strhodes}
809135446Strhodes
810135446Strhodesvoid
811224092Sdougbdns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
812135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
813224092Sdougb	REQUIRE(ring != NULL);
814224092Sdougb	if (view->dynamickeys != NULL)
815224092Sdougb		dns_tsigkeyring_detach(&view->dynamickeys);
816224092Sdougb	dns_tsigkeyring_attach(ring, &view->dynamickeys);
817135446Strhodes}
818135446Strhodes
819224092Sdougbvoid
820224092Sdougbdns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
821224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
822224092Sdougb	REQUIRE(ringp != NULL && *ringp == NULL);
823224092Sdougb	if (view->dynamickeys != NULL)
824224092Sdougb		dns_tsigkeyring_attach(view->dynamickeys, ringp);
825224092Sdougb}
826135446Strhodes
827224092Sdougbvoid
828224092Sdougbdns_view_restorekeyring(dns_view_t *view) {
829224092Sdougb	FILE *fp;
830224092Sdougb	char keyfile[20];
831224092Sdougb	int n;
832224092Sdougb
833135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
834135446Strhodes
835224092Sdougb	if (view->dynamickeys != NULL) {
836224092Sdougb		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
837224092Sdougb			     view->name);
838224092Sdougb		if (n > 0 && (size_t)n < sizeof(keyfile)) {
839224092Sdougb			fp = fopen(keyfile, "r");
840224092Sdougb			if (fp != NULL) {
841224092Sdougb				dns_keyring_restore(view->dynamickeys, fp);
842224092Sdougb				(void)fclose(fp);
843224092Sdougb			}
844224092Sdougb		}
845224092Sdougb	}
846224092Sdougb}
847135446Strhodes
848224092Sdougbvoid
849224092Sdougbdns_view_setdstport(dns_view_t *view, in_port_t dstport) {
850224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
851224092Sdougb	view->dstport = dstport;
852135446Strhodes}
853135446Strhodes
854135446Strhodesvoid
855135446Strhodesdns_view_freeze(dns_view_t *view) {
856135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
857135446Strhodes	REQUIRE(!view->frozen);
858135446Strhodes
859135446Strhodes	if (view->resolver != NULL) {
860135446Strhodes		INSIST(view->cachedb != NULL);
861135446Strhodes		dns_resolver_freeze(view->resolver);
862135446Strhodes	}
863135446Strhodes	view->frozen = ISC_TRUE;
864135446Strhodes}
865135446Strhodes
866224092Sdougb#ifdef BIND9
867224092Sdougbvoid
868224092Sdougbdns_view_thaw(dns_view_t *view) {
869224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
870224092Sdougb	REQUIRE(view->frozen);
871224092Sdougb
872224092Sdougb	view->frozen = ISC_FALSE;
873224092Sdougb}
874224092Sdougb
875135446Strhodesisc_result_t
876224092Sdougbdns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
877224092Sdougb	isc_result_t result;
878224092Sdougb
879224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
880224092Sdougb	REQUIRE(!view->frozen);
881262706Serwin	REQUIRE(view->zonetable != NULL);
882224092Sdougb
883224092Sdougb	result = dns_zt_mount(view->zonetable, zone);
884224092Sdougb
885224092Sdougb	return (result);
886224092Sdougb}
887224092Sdougb#endif
888224092Sdougb
889224092Sdougb#ifdef BIND9
890224092Sdougbisc_result_t
891135446Strhodesdns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
892135446Strhodes	isc_result_t result;
893135446Strhodes
894135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
895135446Strhodes
896262706Serwin	LOCK(&view->lock);
897254402Serwin	if (view->zonetable != NULL) {
898254402Serwin		result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
899254402Serwin		if (result == DNS_R_PARTIALMATCH) {
900254402Serwin			dns_zone_detach(zonep);
901254402Serwin			result = ISC_R_NOTFOUND;
902254402Serwin		}
903254402Serwin	} else
904135446Strhodes		result = ISC_R_NOTFOUND;
905262706Serwin	UNLOCK(&view->lock);
906135446Strhodes
907135446Strhodes	return (result);
908135446Strhodes}
909224092Sdougb#endif
910135446Strhodes
911135446Strhodesisc_result_t
912135446Strhodesdns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
913135446Strhodes	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
914135446Strhodes	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
915224092Sdougb	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
916224092Sdougb	return (dns_view_find2(view, name, type, now, options, use_hints,
917224092Sdougb			       ISC_FALSE, dbp, nodep, foundname, rdataset,
918224092Sdougb			       sigrdataset));
919224092Sdougb}
920224092Sdougb
921224092Sdougbisc_result_t
922224092Sdougbdns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
923224092Sdougb	       isc_stdtime_t now, unsigned int options,
924224092Sdougb	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
925224092Sdougb	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
926224092Sdougb	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
927135446Strhodes{
928135446Strhodes	isc_result_t result;
929135446Strhodes	dns_db_t *db, *zdb;
930135446Strhodes	dns_dbnode_t *node, *znode;
931224092Sdougb	isc_boolean_t is_cache, is_staticstub_zone;
932135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
933135446Strhodes	dns_zone_t *zone;
934135446Strhodes
935224092Sdougb#ifndef BIND9
936224092Sdougb	UNUSED(use_hints);
937224092Sdougb	UNUSED(use_static_stub);
938254402Serwin	UNUSED(zone);
939224092Sdougb#endif
940224092Sdougb
941135446Strhodes	/*
942135446Strhodes	 * Find an rdataset whose owner name is 'name', and whose type is
943135446Strhodes	 * 'type'.
944135446Strhodes	 */
945135446Strhodes
946135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
947135446Strhodes	REQUIRE(view->frozen);
948135446Strhodes	REQUIRE(type != dns_rdatatype_rrsig);
949135446Strhodes	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
950174187Sdougb	REQUIRE(nodep == NULL || *nodep == NULL);
951135446Strhodes
952135446Strhodes	/*
953135446Strhodes	 * Initialize.
954135446Strhodes	 */
955135446Strhodes	dns_rdataset_init(&zrdataset);
956135446Strhodes	dns_rdataset_init(&zsigrdataset);
957135446Strhodes	zdb = NULL;
958135446Strhodes	znode = NULL;
959135446Strhodes
960135446Strhodes	/*
961135446Strhodes	 * Find a database to answer the query.
962135446Strhodes	 */
963135446Strhodes	db = NULL;
964135446Strhodes	node = NULL;
965224092Sdougb	is_staticstub_zone = ISC_FALSE;
966224092Sdougb#ifdef BIND9
967254402Serwin	zone = NULL;
968262706Serwin	LOCK(&view->lock);
969262706Serwin	if (view->zonetable != NULL)
970262706Serwin		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
971262706Serwin	else
972262706Serwin		result = ISC_R_NOTFOUND;
973262706Serwin	UNLOCK(&view->lock);
974224092Sdougb	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
975224092Sdougb	    !use_static_stub) {
976224092Sdougb		result = ISC_R_NOTFOUND;
977224092Sdougb	}
978135446Strhodes	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
979135446Strhodes		result = dns_zone_getdb(zone, &db);
980135446Strhodes		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
981135446Strhodes			dns_db_attach(view->cachedb, &db);
982135446Strhodes		else if (result != ISC_R_SUCCESS)
983135446Strhodes			goto cleanup;
984224092Sdougb		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
985224092Sdougb		    dns_name_equal(name, dns_zone_getorigin(zone))) {
986224092Sdougb			is_staticstub_zone = ISC_TRUE;
987224092Sdougb		}
988135446Strhodes	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
989135446Strhodes		dns_db_attach(view->cachedb, &db);
990224092Sdougb#else
991224092Sdougb	result = ISC_R_NOTFOUND;
992224092Sdougb	if (view->cachedb != NULL)
993224092Sdougb		dns_db_attach(view->cachedb, &db);
994224092Sdougb#endif /* BIND9 */
995135446Strhodes	else
996135446Strhodes		goto cleanup;
997135446Strhodes
998135446Strhodes	is_cache = dns_db_iscache(db);
999135446Strhodes
1000135446Strhodes db_find:
1001135446Strhodes	/*
1002135446Strhodes	 * Now look for an answer in the database.
1003135446Strhodes	 */
1004135446Strhodes	result = dns_db_find(db, name, NULL, type, options,
1005135446Strhodes			     now, &node, foundname, rdataset, sigrdataset);
1006135446Strhodes
1007224092Sdougb	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
1008135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1009135446Strhodes			dns_rdataset_disassociate(rdataset);
1010135446Strhodes		if (sigrdataset != NULL &&
1011135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1012135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1013135446Strhodes		if (node != NULL)
1014135446Strhodes			dns_db_detachnode(db, &node);
1015135446Strhodes		if (!is_cache) {
1016135446Strhodes			dns_db_detach(&db);
1017224092Sdougb			if (view->cachedb != NULL && !is_staticstub_zone) {
1018135446Strhodes				/*
1019135446Strhodes				 * Either the answer is in the cache, or we
1020135446Strhodes				 * don't know it.
1021224092Sdougb				 * Note that if the result comes from a
1022224092Sdougb				 * static-stub zone we stop the search here
1023224092Sdougb				 * (see the function description in view.h).
1024135446Strhodes				 */
1025135446Strhodes				is_cache = ISC_TRUE;
1026135446Strhodes				dns_db_attach(view->cachedb, &db);
1027135446Strhodes				goto db_find;
1028135446Strhodes			}
1029135446Strhodes		} else {
1030135446Strhodes			/*
1031135446Strhodes			 * We don't have the data in the cache.  If we've got
1032135446Strhodes			 * glue from the zone, use it.
1033135446Strhodes			 */
1034135446Strhodes			if (dns_rdataset_isassociated(&zrdataset)) {
1035135446Strhodes				dns_rdataset_clone(&zrdataset, rdataset);
1036135446Strhodes				if (sigrdataset != NULL &&
1037135446Strhodes				    dns_rdataset_isassociated(&zsigrdataset))
1038135446Strhodes					dns_rdataset_clone(&zsigrdataset,
1039135446Strhodes							   sigrdataset);
1040135446Strhodes				result = DNS_R_GLUE;
1041135446Strhodes				if (db != NULL)
1042135446Strhodes					dns_db_detach(&db);
1043135446Strhodes				dns_db_attach(zdb, &db);
1044135446Strhodes				dns_db_attachnode(db, znode, &node);
1045135446Strhodes				goto cleanup;
1046135446Strhodes			}
1047135446Strhodes		}
1048135446Strhodes		/*
1049135446Strhodes		 * We don't know the answer.
1050135446Strhodes		 */
1051135446Strhodes		result = ISC_R_NOTFOUND;
1052135446Strhodes	} else if (result == DNS_R_GLUE) {
1053224092Sdougb		if (view->cachedb != NULL && !is_staticstub_zone) {
1054135446Strhodes			/*
1055135446Strhodes			 * We found an answer, but the cache may be better.
1056135446Strhodes			 * Remember what we've got and go look in the cache.
1057135446Strhodes			 */
1058135446Strhodes			is_cache = ISC_TRUE;
1059135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
1060135446Strhodes			dns_rdataset_disassociate(rdataset);
1061135446Strhodes			if (sigrdataset != NULL &&
1062135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
1063135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1064135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1065135446Strhodes			}
1066135446Strhodes			dns_db_attach(db, &zdb);
1067135446Strhodes			dns_db_attachnode(zdb, node, &znode);
1068135446Strhodes			dns_db_detachnode(db, &node);
1069135446Strhodes			dns_db_detach(&db);
1070135446Strhodes			dns_db_attach(view->cachedb, &db);
1071135446Strhodes			goto db_find;
1072135446Strhodes		}
1073135446Strhodes		/*
1074135446Strhodes		 * Otherwise, the glue is the best answer.
1075135446Strhodes		 */
1076135446Strhodes		result = ISC_R_SUCCESS;
1077135446Strhodes	}
1078135446Strhodes
1079224092Sdougb#ifdef BIND9
1080135446Strhodes	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1081135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1082135446Strhodes			dns_rdataset_disassociate(rdataset);
1083135446Strhodes		if (sigrdataset != NULL &&
1084135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1085135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1086135446Strhodes		if (db != NULL) {
1087135446Strhodes			if (node != NULL)
1088135446Strhodes				dns_db_detachnode(db, &node);
1089135446Strhodes			dns_db_detach(&db);
1090135446Strhodes		}
1091135446Strhodes		result = dns_db_find(view->hints, name, NULL, type, options,
1092135446Strhodes				     now, &node, foundname,
1093135446Strhodes				     rdataset, sigrdataset);
1094135446Strhodes		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1095135446Strhodes			/*
1096135446Strhodes			 * We just used a hint.  Let the resolver know it
1097135446Strhodes			 * should consider priming.
1098135446Strhodes			 */
1099135446Strhodes			dns_resolver_prime(view->resolver);
1100135446Strhodes			dns_db_attach(view->hints, &db);
1101135446Strhodes			result = DNS_R_HINT;
1102135446Strhodes		} else if (result == DNS_R_NXRRSET) {
1103135446Strhodes			dns_db_attach(view->hints, &db);
1104135446Strhodes			result = DNS_R_HINTNXRRSET;
1105135446Strhodes		} else if (result == DNS_R_NXDOMAIN)
1106135446Strhodes			result = ISC_R_NOTFOUND;
1107135446Strhodes
1108135446Strhodes		/*
1109135446Strhodes		 * Cleanup if non-standard hints are used.
1110135446Strhodes		 */
1111135446Strhodes		if (db == NULL && node != NULL)
1112135446Strhodes			dns_db_detachnode(view->hints, &node);
1113135446Strhodes	}
1114224092Sdougb#endif /* BIND9 */
1115135446Strhodes
1116135446Strhodes cleanup:
1117135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
1118135446Strhodes		dns_rdataset_disassociate(&zrdataset);
1119135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
1120135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
1121135446Strhodes	}
1122135446Strhodes
1123135446Strhodes	if (zdb != NULL) {
1124135446Strhodes		if (znode != NULL)
1125135446Strhodes			dns_db_detachnode(zdb, &znode);
1126135446Strhodes		dns_db_detach(&zdb);
1127135446Strhodes	}
1128135446Strhodes
1129135446Strhodes	if (db != NULL) {
1130135446Strhodes		if (node != NULL) {
1131135446Strhodes			if (nodep != NULL)
1132135446Strhodes				*nodep = node;
1133135446Strhodes			else
1134135446Strhodes				dns_db_detachnode(db, &node);
1135135446Strhodes		}
1136135446Strhodes		if (dbp != NULL)
1137135446Strhodes			*dbp = db;
1138135446Strhodes		else
1139135446Strhodes			dns_db_detach(&db);
1140135446Strhodes	} else
1141135446Strhodes		INSIST(node == NULL);
1142135446Strhodes
1143224092Sdougb#ifdef BIND9
1144135446Strhodes	if (zone != NULL)
1145135446Strhodes		dns_zone_detach(&zone);
1146224092Sdougb#endif
1147135446Strhodes
1148135446Strhodes	return (result);
1149135446Strhodes}
1150135446Strhodes
1151135446Strhodesisc_result_t
1152135446Strhodesdns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1153135446Strhodes		    isc_stdtime_t now, unsigned int options,
1154135446Strhodes		    isc_boolean_t use_hints,
1155135446Strhodes		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1156135446Strhodes{
1157135446Strhodes	isc_result_t result;
1158135446Strhodes	dns_fixedname_t foundname;
1159135446Strhodes
1160135446Strhodes	dns_fixedname_init(&foundname);
1161135446Strhodes	result = dns_view_find(view, name, type, now, options, use_hints,
1162135446Strhodes			       NULL, NULL, dns_fixedname_name(&foundname),
1163135446Strhodes			       rdataset, sigrdataset);
1164135446Strhodes	if (result == DNS_R_NXDOMAIN) {
1165135446Strhodes		/*
1166135446Strhodes		 * The rdataset and sigrdataset of the relevant NSEC record
1167135446Strhodes		 * may be returned, but the caller cannot use them because
1168135446Strhodes		 * foundname is not returned by this simplified API.  We
1169135446Strhodes		 * disassociate them here to prevent any misuse by the caller.
1170135446Strhodes		 */
1171135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1172135446Strhodes			dns_rdataset_disassociate(rdataset);
1173135446Strhodes		if (sigrdataset != NULL &&
1174135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1175135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1176135446Strhodes	} else if (result != ISC_R_SUCCESS &&
1177135446Strhodes		   result != DNS_R_GLUE &&
1178135446Strhodes		   result != DNS_R_HINT &&
1179135446Strhodes		   result != DNS_R_NCACHENXDOMAIN &&
1180135446Strhodes		   result != DNS_R_NCACHENXRRSET &&
1181135446Strhodes		   result != DNS_R_NXRRSET &&
1182135446Strhodes		   result != DNS_R_HINTNXRRSET &&
1183135446Strhodes		   result != ISC_R_NOTFOUND) {
1184135446Strhodes		if (dns_rdataset_isassociated(rdataset))
1185135446Strhodes			dns_rdataset_disassociate(rdataset);
1186135446Strhodes		if (sigrdataset != NULL &&
1187135446Strhodes		    dns_rdataset_isassociated(sigrdataset))
1188135446Strhodes			dns_rdataset_disassociate(sigrdataset);
1189135446Strhodes		result = ISC_R_NOTFOUND;
1190135446Strhodes	}
1191135446Strhodes
1192135446Strhodes	return (result);
1193135446Strhodes}
1194135446Strhodes
1195135446Strhodesisc_result_t
1196135446Strhodesdns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1197135446Strhodes		     isc_stdtime_t now, unsigned int options,
1198186462Sdougb		     isc_boolean_t use_hints,
1199135446Strhodes		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1200135446Strhodes{
1201135446Strhodes	return(dns_view_findzonecut2(view, name, fname, now, options,
1202135446Strhodes				     use_hints, ISC_TRUE,
1203135446Strhodes				     rdataset, sigrdataset));
1204135446Strhodes}
1205135446Strhodes
1206135446Strhodesisc_result_t
1207135446Strhodesdns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1208135446Strhodes		      isc_stdtime_t now, unsigned int options,
1209224092Sdougb		      isc_boolean_t use_hints,	isc_boolean_t use_cache,
1210135446Strhodes		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1211135446Strhodes{
1212135446Strhodes	isc_result_t result;
1213135446Strhodes	dns_db_t *db;
1214225361Sdougb	isc_boolean_t is_cache, use_zone, try_hints;
1215135446Strhodes	dns_zone_t *zone;
1216135446Strhodes	dns_name_t *zfname;
1217135446Strhodes	dns_rdataset_t zrdataset, zsigrdataset;
1218135446Strhodes	dns_fixedname_t zfixedname;
1219135446Strhodes
1220254402Serwin#ifndef BIND9
1221254402Serwin	UNUSED(zone);
1222254402Serwin#endif
1223254402Serwin
1224135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1225135446Strhodes	REQUIRE(view->frozen);
1226135446Strhodes
1227135446Strhodes	db = NULL;
1228135446Strhodes	use_zone = ISC_FALSE;
1229135446Strhodes	try_hints = ISC_FALSE;
1230135446Strhodes	zfname = NULL;
1231135446Strhodes
1232135446Strhodes	/*
1233135446Strhodes	 * Initialize.
1234135446Strhodes	 */
1235135446Strhodes	dns_fixedname_init(&zfixedname);
1236135446Strhodes	dns_rdataset_init(&zrdataset);
1237135446Strhodes	dns_rdataset_init(&zsigrdataset);
1238135446Strhodes
1239135446Strhodes	/*
1240135446Strhodes	 * Find the right database.
1241135446Strhodes	 */
1242224092Sdougb#ifdef BIND9
1243254402Serwin	zone = NULL;
1244262706Serwin	LOCK(&view->lock);
1245262706Serwin	if (view->zonetable != NULL)
1246262706Serwin		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1247262706Serwin	else
1248262706Serwin		result = ISC_R_NOTFOUND;
1249225361Sdougb	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1250135446Strhodes		result = dns_zone_getdb(zone, &db);
1251262706Serwin	UNLOCK(&view->lock);
1252224092Sdougb#else
1253224092Sdougb	result = ISC_R_NOTFOUND;
1254224092Sdougb#endif
1255135446Strhodes	if (result == ISC_R_NOTFOUND) {
1256135446Strhodes		/*
1257135446Strhodes		 * We're not directly authoritative for this query name, nor
1258135446Strhodes		 * is it a subdomain of any zone for which we're
1259135446Strhodes		 * authoritative.
1260135446Strhodes		 */
1261135446Strhodes		if (use_cache && view->cachedb != NULL) {
1262135446Strhodes			/*
1263135446Strhodes			 * We have a cache; try it.
1264135446Strhodes			 */
1265135446Strhodes			dns_db_attach(view->cachedb, &db);
1266135446Strhodes		} else {
1267135446Strhodes			/*
1268135446Strhodes			 * Maybe we have hints...
1269135446Strhodes			 */
1270135446Strhodes			try_hints = ISC_TRUE;
1271135446Strhodes			goto finish;
1272135446Strhodes		}
1273135446Strhodes	} else if (result != ISC_R_SUCCESS) {
1274135446Strhodes		/*
1275135446Strhodes		 * Something is broken.
1276135446Strhodes		 */
1277135446Strhodes		goto cleanup;
1278135446Strhodes	}
1279135446Strhodes	is_cache = dns_db_iscache(db);
1280135446Strhodes
1281135446Strhodes db_find:
1282135446Strhodes	/*
1283135446Strhodes	 * Look for the zonecut.
1284135446Strhodes	 */
1285135446Strhodes	if (!is_cache) {
1286135446Strhodes		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1287135446Strhodes				     now, NULL, fname, rdataset, sigrdataset);
1288135446Strhodes		if (result == DNS_R_DELEGATION)
1289135446Strhodes			result = ISC_R_SUCCESS;
1290135446Strhodes		else if (result != ISC_R_SUCCESS)
1291135446Strhodes			goto cleanup;
1292135446Strhodes		if (use_cache && view->cachedb != NULL && db != view->hints) {
1293135446Strhodes			/*
1294135446Strhodes			 * We found an answer, but the cache may be better.
1295135446Strhodes			 */
1296135446Strhodes			zfname = dns_fixedname_name(&zfixedname);
1297135446Strhodes			result = dns_name_copy(fname, zfname, NULL);
1298135446Strhodes			if (result != ISC_R_SUCCESS)
1299135446Strhodes				goto cleanup;
1300135446Strhodes			dns_rdataset_clone(rdataset, &zrdataset);
1301135446Strhodes			dns_rdataset_disassociate(rdataset);
1302135446Strhodes			if (sigrdataset != NULL &&
1303135446Strhodes			    dns_rdataset_isassociated(sigrdataset)) {
1304135446Strhodes				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1305135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1306135446Strhodes			}
1307135446Strhodes			dns_db_detach(&db);
1308135446Strhodes			dns_db_attach(view->cachedb, &db);
1309135446Strhodes			is_cache = ISC_TRUE;
1310135446Strhodes			goto db_find;
1311135446Strhodes		}
1312135446Strhodes	} else {
1313135446Strhodes		result = dns_db_findzonecut(db, name, options, now, NULL,
1314135446Strhodes					    fname, rdataset, sigrdataset);
1315135446Strhodes		if (result == ISC_R_SUCCESS) {
1316135446Strhodes			if (zfname != NULL &&
1317224092Sdougb			    (!dns_name_issubdomain(fname, zfname) ||
1318224092Sdougb			     (dns_zone_staticstub &&
1319224092Sdougb			      dns_name_equal(fname, zfname)))) {
1320135446Strhodes				/*
1321135446Strhodes				 * We found a zonecut in the cache, but our
1322135446Strhodes				 * zone delegation is better.
1323135446Strhodes				 */
1324135446Strhodes				use_zone = ISC_TRUE;
1325135446Strhodes			}
1326135446Strhodes		} else if (result == ISC_R_NOTFOUND) {
1327135446Strhodes			if (zfname != NULL) {
1328135446Strhodes				/*
1329135446Strhodes				 * We didn't find anything in the cache, but we
1330135446Strhodes				 * have a zone delegation, so use it.
1331135446Strhodes				 */
1332135446Strhodes				use_zone = ISC_TRUE;
1333135446Strhodes			} else {
1334135446Strhodes				/*
1335135446Strhodes				 * Maybe we have hints...
1336135446Strhodes				 */
1337135446Strhodes				try_hints = ISC_TRUE;
1338135446Strhodes			}
1339135446Strhodes		} else {
1340135446Strhodes			/*
1341135446Strhodes			 * Something bad happened.
1342135446Strhodes			 */
1343135446Strhodes			goto cleanup;
1344135446Strhodes		}
1345135446Strhodes	}
1346135446Strhodes
1347135446Strhodes finish:
1348135446Strhodes	if (use_zone) {
1349135446Strhodes		if (dns_rdataset_isassociated(rdataset)) {
1350135446Strhodes			dns_rdataset_disassociate(rdataset);
1351135446Strhodes			if (sigrdataset != NULL &&
1352135446Strhodes			    dns_rdataset_isassociated(sigrdataset))
1353135446Strhodes				dns_rdataset_disassociate(sigrdataset);
1354135446Strhodes		}
1355135446Strhodes		result = dns_name_copy(zfname, fname, NULL);
1356135446Strhodes		if (result != ISC_R_SUCCESS)
1357135446Strhodes			goto cleanup;
1358135446Strhodes		dns_rdataset_clone(&zrdataset, rdataset);
1359135446Strhodes		if (sigrdataset != NULL &&
1360135446Strhodes		    dns_rdataset_isassociated(&zrdataset))
1361135446Strhodes			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1362135446Strhodes	} else if (try_hints && use_hints && view->hints != NULL) {
1363135446Strhodes		/*
1364135446Strhodes		 * We've found nothing so far, but we have hints.
1365135446Strhodes		 */
1366135446Strhodes		result = dns_db_find(view->hints, dns_rootname, NULL,
1367135446Strhodes				     dns_rdatatype_ns, 0, now, NULL, fname,
1368135446Strhodes				     rdataset, NULL);
1369135446Strhodes		if (result != ISC_R_SUCCESS) {
1370135446Strhodes			/*
1371135446Strhodes			 * We can't even find the hints for the root
1372135446Strhodes			 * nameservers!
1373135446Strhodes			 */
1374135446Strhodes			if (dns_rdataset_isassociated(rdataset))
1375135446Strhodes				dns_rdataset_disassociate(rdataset);
1376135446Strhodes			result = ISC_R_NOTFOUND;
1377135446Strhodes		}
1378135446Strhodes	}
1379135446Strhodes
1380135446Strhodes cleanup:
1381135446Strhodes	if (dns_rdataset_isassociated(&zrdataset)) {
1382135446Strhodes		dns_rdataset_disassociate(&zrdataset);
1383135446Strhodes		if (dns_rdataset_isassociated(&zsigrdataset))
1384135446Strhodes			dns_rdataset_disassociate(&zsigrdataset);
1385135446Strhodes	}
1386135446Strhodes	if (db != NULL)
1387135446Strhodes		dns_db_detach(&db);
1388224092Sdougb#ifdef BIND9
1389135446Strhodes	if (zone != NULL)
1390135446Strhodes		dns_zone_detach(&zone);
1391224092Sdougb#endif
1392135446Strhodes
1393135446Strhodes	return (result);
1394135446Strhodes}
1395135446Strhodes
1396135446Strhodesisc_result_t
1397135446Strhodesdns_viewlist_find(dns_viewlist_t *list, const char *name,
1398135446Strhodes		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1399135446Strhodes{
1400135446Strhodes	dns_view_t *view;
1401135446Strhodes
1402135446Strhodes	REQUIRE(list != NULL);
1403135446Strhodes
1404135446Strhodes	for (view = ISC_LIST_HEAD(*list);
1405135446Strhodes	     view != NULL;
1406135446Strhodes	     view = ISC_LIST_NEXT(view, link)) {
1407135446Strhodes		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1408135446Strhodes			break;
1409135446Strhodes	}
1410135446Strhodes	if (view == NULL)
1411135446Strhodes		return (ISC_R_NOTFOUND);
1412135446Strhodes
1413135446Strhodes	dns_view_attach(view, viewp);
1414135446Strhodes
1415135446Strhodes	return (ISC_R_SUCCESS);
1416135446Strhodes}
1417135446Strhodes
1418224092Sdougb#ifdef BIND9
1419135446Strhodesisc_result_t
1420193149Sdougbdns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1421193149Sdougb		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1422193149Sdougb		      dns_zone_t **zonep)
1423193149Sdougb{
1424193149Sdougb	dns_view_t *view;
1425193149Sdougb	isc_result_t result;
1426193149Sdougb	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1427193149Sdougb	dns_zone_t **zp = NULL;;
1428193149Sdougb
1429193149Sdougb	REQUIRE(list != NULL);
1430262706Serwin	REQUIRE(zonep != NULL && *zonep == NULL);
1431262706Serwin
1432193149Sdougb	for (view = ISC_LIST_HEAD(*list);
1433193149Sdougb	     view != NULL;
1434193149Sdougb	     view = ISC_LIST_NEXT(view, link)) {
1435193149Sdougb		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1436193149Sdougb			continue;
1437193149Sdougb
1438193149Sdougb		/*
1439193149Sdougb		 * If the zone is defined in more than one view,
1440193149Sdougb		 * treat it as not found.
1441193149Sdougb		 */
1442193149Sdougb		zp = (zone1 == NULL) ? &zone1 : &zone2;
1443262706Serwin		LOCK(&view->lock);
1444262706Serwin		if (view->zonetable != NULL)
1445262706Serwin			result = dns_zt_find(view->zonetable, name, 0,
1446262706Serwin					     NULL, zp);
1447262706Serwin		else
1448262706Serwin			result = ISC_R_NOTFOUND;
1449262706Serwin		UNLOCK(&view->lock);
1450193149Sdougb		INSIST(result == ISC_R_SUCCESS ||
1451193149Sdougb		       result == ISC_R_NOTFOUND ||
1452193149Sdougb		       result == DNS_R_PARTIALMATCH);
1453193149Sdougb
1454193149Sdougb		/* Treat a partial match as no match */
1455193149Sdougb		if (result == DNS_R_PARTIALMATCH) {
1456193149Sdougb			dns_zone_detach(zp);
1457193149Sdougb			result = ISC_R_NOTFOUND;
1458225361Sdougb			POST(result);
1459193149Sdougb		}
1460193149Sdougb
1461193149Sdougb		if (zone2 != NULL) {
1462193149Sdougb			dns_zone_detach(&zone1);
1463193149Sdougb			dns_zone_detach(&zone2);
1464193149Sdougb			return (ISC_R_NOTFOUND);
1465193149Sdougb		}
1466193149Sdougb	}
1467193149Sdougb
1468193149Sdougb	if (zone1 != NULL) {
1469193149Sdougb		dns_zone_attach(zone1, zonep);
1470193149Sdougb		dns_zone_detach(&zone1);
1471193149Sdougb		return (ISC_R_SUCCESS);
1472193149Sdougb	}
1473193149Sdougb
1474193149Sdougb	return (ISC_R_NOTFOUND);
1475193149Sdougb}
1476193149Sdougb
1477193149Sdougbisc_result_t
1478135446Strhodesdns_view_load(dns_view_t *view, isc_boolean_t stop) {
1479135446Strhodes
1480135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1481254897Serwin	REQUIRE(view->zonetable != NULL);
1482135446Strhodes
1483135446Strhodes	return (dns_zt_load(view->zonetable, stop));
1484135446Strhodes}
1485135446Strhodes
1486135446Strhodesisc_result_t
1487135446Strhodesdns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1488135446Strhodes
1489135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1490254897Serwin	REQUIRE(view->zonetable != NULL);
1491135446Strhodes
1492135446Strhodes	return (dns_zt_loadnew(view->zonetable, stop));
1493135446Strhodes}
1494254897Serwin
1495254897Serwinisc_result_t
1496254897Serwindns_view_asyncload(dns_view_t *view, dns_zt_allloaded_t callback, void *arg) {
1497254897Serwin	REQUIRE(DNS_VIEW_VALID(view));
1498254897Serwin	REQUIRE(view->zonetable != NULL);
1499254897Serwin
1500254897Serwin	return (dns_zt_asyncload(view->zonetable, callback, arg));
1501254897Serwin}
1502254897Serwin
1503254897Serwin
1504224092Sdougb#endif /* BIND9 */
1505135446Strhodes
1506135446Strhodesisc_result_t
1507135446Strhodesdns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1508135446Strhodes{
1509135446Strhodes	isc_result_t result;
1510135446Strhodes	REQUIRE(keyp != NULL && *keyp == NULL);
1511135446Strhodes
1512135446Strhodes	result = dns_tsigkey_find(keyp, keyname, NULL,
1513135446Strhodes				  view->statickeys);
1514135446Strhodes	if (result == ISC_R_NOTFOUND)
1515135446Strhodes		result = dns_tsigkey_find(keyp, keyname, NULL,
1516135446Strhodes					  view->dynamickeys);
1517135446Strhodes	return (result);
1518135446Strhodes}
1519135446Strhodes
1520135446Strhodesisc_result_t
1521135446Strhodesdns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1522135446Strhodes		     dns_tsigkey_t **keyp)
1523135446Strhodes{
1524135446Strhodes	isc_result_t result;
1525135446Strhodes	dns_name_t *keyname = NULL;
1526135446Strhodes	dns_peer_t *peer = NULL;
1527135446Strhodes
1528135446Strhodes	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1529135446Strhodes	if (result != ISC_R_SUCCESS)
1530135446Strhodes		return (result);
1531135446Strhodes
1532135446Strhodes	result = dns_peer_getkey(peer, &keyname);
1533135446Strhodes	if (result != ISC_R_SUCCESS)
1534135446Strhodes		return (result);
1535135446Strhodes
1536204619Sdougb	result = dns_view_gettsig(view, keyname, keyp);
1537204619Sdougb	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1538135446Strhodes}
1539135446Strhodes
1540135446Strhodesisc_result_t
1541135446Strhodesdns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1542135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1543135446Strhodes	REQUIRE(source != NULL);
1544135446Strhodes
1545135446Strhodes	return (dns_tsig_verify(source, msg, view->statickeys,
1546135446Strhodes				view->dynamickeys));
1547135446Strhodes}
1548135446Strhodes
1549224092Sdougb#ifdef BIND9
1550135446Strhodesisc_result_t
1551135446Strhodesdns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1552135446Strhodes	isc_result_t result;
1553135446Strhodes
1554135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1555135446Strhodes
1556135446Strhodes	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1557135446Strhodes	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1558205292Sdougb					 &dns_master_style_cache, fp);
1559135446Strhodes	if (result != ISC_R_SUCCESS)
1560135446Strhodes		return (result);
1561135446Strhodes	dns_adb_dump(view->adb, fp);
1562205292Sdougb	dns_resolver_printbadcache(view->resolver, fp);
1563135446Strhodes	return (ISC_R_SUCCESS);
1564135446Strhodes}
1565224092Sdougb#endif
1566135446Strhodes
1567135446Strhodesisc_result_t
1568135446Strhodesdns_view_flushcache(dns_view_t *view) {
1569224092Sdougb	return (dns_view_flushcache2(view, ISC_FALSE));
1570224092Sdougb}
1571224092Sdougb
1572224092Sdougbisc_result_t
1573224092Sdougbdns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1574135446Strhodes	isc_result_t result;
1575135446Strhodes
1576135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1577135446Strhodes
1578135446Strhodes	if (view->cachedb == NULL)
1579135446Strhodes		return (ISC_R_SUCCESS);
1580224092Sdougb	if (!fixuponly) {
1581224092Sdougb		result = dns_cache_flush(view->cache);
1582224092Sdougb		if (result != ISC_R_SUCCESS)
1583224092Sdougb			return (result);
1584224092Sdougb	}
1585224092Sdougb#ifdef BIND9
1586170222Sdougb	if (view->acache != NULL)
1587170222Sdougb		dns_acache_putdb(view->acache, view->cachedb);
1588224092Sdougb#endif
1589135446Strhodes	dns_db_detach(&view->cachedb);
1590135446Strhodes	dns_cache_attachdb(view->cache, &view->cachedb);
1591224092Sdougb#ifdef BIND9
1592170222Sdougb	if (view->acache != NULL)
1593170222Sdougb		dns_acache_setdb(view->acache, view->cachedb);
1594205292Sdougb	if (view->resolver != NULL)
1595205292Sdougb		dns_resolver_flushbadcache(view->resolver, NULL);
1596224092Sdougb#endif
1597135446Strhodes
1598135446Strhodes	dns_adb_flush(view->adb);
1599135446Strhodes	return (ISC_R_SUCCESS);
1600135446Strhodes}
1601135446Strhodes
1602135446Strhodesisc_result_t
1603135446Strhodesdns_view_flushname(dns_view_t *view, dns_name_t *name) {
1604254897Serwin	return (dns_view_flushnode(view, name, ISC_FALSE));
1605254897Serwin}
1606135446Strhodes
1607254897Serwinisc_result_t
1608254897Serwindns_view_flushnode(dns_view_t *view, dns_name_t *name, isc_boolean_t tree) {
1609254897Serwin
1610135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1611135446Strhodes
1612254897Serwin	if (!tree) {
1613254897Serwin		if (view->adb != NULL)
1614254897Serwin			dns_adb_flushname(view->adb, name);
1615254897Serwin		if (view->cache == NULL)
1616254897Serwin			return (ISC_R_SUCCESS);
1617254897Serwin		if (view->resolver != NULL)
1618254897Serwin			dns_resolver_flushbadcache(view->resolver, name);
1619254897Serwin	}
1620254897Serwin	return (dns_cache_flushnode(view->cache, name, tree));
1621135446Strhodes}
1622135446Strhodes
1623135446Strhodesisc_result_t
1624135446Strhodesdns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1625135446Strhodes	isc_result_t result;
1626135446Strhodes	dns_name_t *new;
1627135446Strhodes	isc_uint32_t hash;
1628135446Strhodes
1629135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1630135446Strhodes
1631135446Strhodes	if (view->delonly == NULL) {
1632135446Strhodes		view->delonly = isc_mem_get(view->mctx,
1633135446Strhodes					    sizeof(dns_namelist_t) *
1634135446Strhodes					    DNS_VIEW_DELONLYHASH);
1635135446Strhodes		if (view->delonly == NULL)
1636135446Strhodes			return (ISC_R_NOMEMORY);
1637135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1638135446Strhodes			ISC_LIST_INIT(view->delonly[hash]);
1639135446Strhodes	}
1640135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1641135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1642135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1643135446Strhodes		new = ISC_LIST_NEXT(new, link);
1644135446Strhodes	if (new != NULL)
1645135446Strhodes		return (ISC_R_SUCCESS);
1646135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1647135446Strhodes	if (new == NULL)
1648135446Strhodes		return (ISC_R_NOMEMORY);
1649135446Strhodes	dns_name_init(new, NULL);
1650135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1651135446Strhodes	if (result == ISC_R_SUCCESS)
1652135446Strhodes		ISC_LIST_APPEND(view->delonly[hash], new, link);
1653135446Strhodes	else
1654135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1655135446Strhodes	return (result);
1656135446Strhodes}
1657135446Strhodes
1658135446Strhodesisc_result_t
1659135446Strhodesdns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1660135446Strhodes	isc_result_t result;
1661135446Strhodes	dns_name_t *new;
1662135446Strhodes	isc_uint32_t hash;
1663135446Strhodes
1664135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1665135446Strhodes
1666135446Strhodes	if (view->rootexclude == NULL) {
1667135446Strhodes		view->rootexclude = isc_mem_get(view->mctx,
1668135446Strhodes					    sizeof(dns_namelist_t) *
1669135446Strhodes					    DNS_VIEW_DELONLYHASH);
1670135446Strhodes		if (view->rootexclude == NULL)
1671135446Strhodes			return (ISC_R_NOMEMORY);
1672135446Strhodes		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1673135446Strhodes			ISC_LIST_INIT(view->rootexclude[hash]);
1674135446Strhodes	}
1675135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1676135446Strhodes	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1677135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1678135446Strhodes		new = ISC_LIST_NEXT(new, link);
1679135446Strhodes	if (new != NULL)
1680135446Strhodes		return (ISC_R_SUCCESS);
1681135446Strhodes	new = isc_mem_get(view->mctx, sizeof(*new));
1682135446Strhodes	if (new == NULL)
1683135446Strhodes		return (ISC_R_NOMEMORY);
1684135446Strhodes	dns_name_init(new, NULL);
1685135446Strhodes	result = dns_name_dup(name, view->mctx, new);
1686135446Strhodes	if (result == ISC_R_SUCCESS)
1687135446Strhodes		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1688135446Strhodes	else
1689135446Strhodes		isc_mem_put(view->mctx, new, sizeof(*new));
1690135446Strhodes	return (result);
1691135446Strhodes}
1692135446Strhodes
1693135446Strhodesisc_boolean_t
1694135446Strhodesdns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1695135446Strhodes	dns_name_t *new;
1696135446Strhodes	isc_uint32_t hash;
1697135446Strhodes
1698135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1699135446Strhodes
1700135446Strhodes	if (!view->rootdelonly && view->delonly == NULL)
1701135446Strhodes		return (ISC_FALSE);
1702135446Strhodes
1703135446Strhodes	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1704135446Strhodes	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1705135446Strhodes		if (view->rootexclude == NULL)
1706135446Strhodes			return (ISC_TRUE);
1707135446Strhodes		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1708135446Strhodes		while (new != NULL && !dns_name_equal(new, name))
1709135446Strhodes			new = ISC_LIST_NEXT(new, link);
1710135446Strhodes		if (new == NULL)
1711135446Strhodes			return (ISC_TRUE);
1712135446Strhodes	}
1713135446Strhodes
1714135446Strhodes	if (view->delonly == NULL)
1715135446Strhodes		return (ISC_FALSE);
1716135446Strhodes
1717135446Strhodes	new = ISC_LIST_HEAD(view->delonly[hash]);
1718135446Strhodes	while (new != NULL && !dns_name_equal(new, name))
1719135446Strhodes		new = ISC_LIST_NEXT(new, link);
1720135446Strhodes	if (new == NULL)
1721135446Strhodes		return (ISC_FALSE);
1722135446Strhodes	return (ISC_TRUE);
1723135446Strhodes}
1724135446Strhodes
1725186462Sdougbvoid
1726135446Strhodesdns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1727135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1728135446Strhodes	view->rootdelonly = value;
1729135446Strhodes}
1730135446Strhodes
1731135446Strhodesisc_boolean_t
1732135446Strhodesdns_view_getrootdelonly(dns_view_t *view) {
1733135446Strhodes	REQUIRE(DNS_VIEW_VALID(view));
1734135446Strhodes	return (view->rootdelonly);
1735135446Strhodes}
1736170222Sdougb
1737224092Sdougb#ifdef BIND9
1738170222Sdougbisc_result_t
1739170222Sdougbdns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1740262706Serwin
1741170222Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1742262706Serwin	REQUIRE(view->zonetable != NULL);
1743262706Serwin
1744170222Sdougb	return (dns_zt_freezezones(view->zonetable, value));
1745170222Sdougb}
1746224092Sdougb#endif
1747193149Sdougb
1748193149Sdougbvoid
1749193149Sdougbdns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1750262706Serwin
1751193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1752193149Sdougb	REQUIRE(!view->frozen);
1753193149Sdougb	REQUIRE(view->resstats == NULL);
1754193149Sdougb
1755193149Sdougb	isc_stats_attach(stats, &view->resstats);
1756193149Sdougb}
1757193149Sdougb
1758193149Sdougbvoid
1759193149Sdougbdns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1760193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1761193149Sdougb	REQUIRE(statsp != NULL && *statsp == NULL);
1762193149Sdougb
1763193149Sdougb	if (view->resstats != NULL)
1764193149Sdougb		isc_stats_attach(view->resstats, statsp);
1765193149Sdougb}
1766193149Sdougb
1767193149Sdougbvoid
1768193149Sdougbdns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1769193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1770193149Sdougb	REQUIRE(!view->frozen);
1771193149Sdougb	REQUIRE(view->resquerystats == NULL);
1772193149Sdougb
1773193149Sdougb	dns_stats_attach(stats, &view->resquerystats);
1774193149Sdougb}
1775193149Sdougb
1776193149Sdougbvoid
1777193149Sdougbdns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1778193149Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1779193149Sdougb	REQUIRE(statsp != NULL && *statsp == NULL);
1780193149Sdougb
1781193149Sdougb	if (view->resquerystats != NULL)
1782193149Sdougb		dns_stats_attach(view->resquerystats, statsp);
1783193149Sdougb}
1784224092Sdougb
1785224092Sdougbisc_result_t
1786224092Sdougbdns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1787224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1788224092Sdougb	if (view->secroots_priv != NULL)
1789224092Sdougb		dns_keytable_detach(&view->secroots_priv);
1790224092Sdougb	return (dns_keytable_create(mctx, &view->secroots_priv));
1791224092Sdougb}
1792224092Sdougb
1793224092Sdougbisc_result_t
1794224092Sdougbdns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1795224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1796224092Sdougb	REQUIRE(ktp != NULL && *ktp == NULL);
1797224092Sdougb	if (view->secroots_priv == NULL)
1798224092Sdougb		return (ISC_R_NOTFOUND);
1799224092Sdougb	dns_keytable_attach(view->secroots_priv, ktp);
1800224092Sdougb	return (ISC_R_SUCCESS);
1801224092Sdougb}
1802224092Sdougb
1803224092Sdougbisc_result_t
1804224092Sdougbdns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1805224092Sdougb			 isc_boolean_t *secure_domain) {
1806224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1807234010Sdougb
1808234010Sdougb	if (view->secroots_priv == NULL)
1809234010Sdougb		return (ISC_R_NOTFOUND);
1810224092Sdougb	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1811224092Sdougb					    secure_domain));
1812224092Sdougb}
1813224092Sdougb
1814224092Sdougbvoid
1815224092Sdougbdns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1816224092Sdougb		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1817224092Sdougb{
1818224092Sdougb	isc_result_t result;
1819224092Sdougb	unsigned char data[4096];
1820224092Sdougb	dns_rdata_t rdata = DNS_RDATA_INIT;
1821224092Sdougb	isc_buffer_t buffer;
1822224092Sdougb	dst_key_t *key = NULL;
1823224092Sdougb	dns_keytable_t *sr = NULL;
1824224092Sdougb
1825224092Sdougb	/*
1826224092Sdougb	 * Clear the revoke bit, if set, so that the key will match what's
1827224092Sdougb	 * in secroots now.
1828224092Sdougb	 */
1829224092Sdougb	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1830224092Sdougb
1831224092Sdougb	/* Convert dnskey to DST key. */
1832224092Sdougb	isc_buffer_init(&buffer, data, sizeof(data));
1833224092Sdougb	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1834224092Sdougb			     dns_rdatatype_dnskey, dnskey, &buffer);
1835224092Sdougb	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1836224092Sdougb	if (result != ISC_R_SUCCESS)
1837224092Sdougb		return;
1838224092Sdougb	result = dns_view_getsecroots(view, &sr);
1839224092Sdougb	if (result == ISC_R_SUCCESS) {
1840224092Sdougb		dns_keytable_deletekeynode(sr, key);
1841224092Sdougb		dns_keytable_detach(&sr);
1842224092Sdougb	}
1843224092Sdougb	dst_key_free(&key);
1844224092Sdougb}
1845224092Sdougb
1846224092Sdougb#define NZF ".nzf"
1847224092Sdougb
1848224092Sdougbvoid
1849224092Sdougbdns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1850224092Sdougb		     void (*cfg_destroy)(void **))
1851224092Sdougb{
1852224092Sdougb	REQUIRE(DNS_VIEW_VALID(view));
1853224092Sdougb	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1854224092Sdougb
1855224092Sdougb#ifdef BIND9
1856224092Sdougb	if (view->new_zone_file != NULL) {
1857224092Sdougb		isc_mem_free(view->mctx, view->new_zone_file);
1858224092Sdougb		view->new_zone_file = NULL;
1859224092Sdougb	}
1860224092Sdougb
1861224092Sdougb	if (view->new_zone_config != NULL) {
1862224092Sdougb		view->cfg_destroy(&view->new_zone_config);
1863224092Sdougb		view->cfg_destroy = NULL;
1864224092Sdougb	}
1865224092Sdougb
1866224092Sdougb	if (allow) {
1867224092Sdougb		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1868224092Sdougb		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1869224092Sdougb		/* Truncate the hash at 16 chars; full length is overkill */
1870224092Sdougb		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1871224092Sdougb		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1872224092Sdougb		view->new_zone_config = cfgctx;
1873224092Sdougb		view->cfg_destroy = cfg_destroy;
1874224092Sdougb	}
1875224092Sdougb#else
1876224092Sdougb	UNUSED(allow);
1877224092Sdougb	UNUSED(cfgctx);
1878224092Sdougb	UNUSED(cfg_destroy);
1879224092Sdougb#endif
1880224092Sdougb}
1881