view.c revision 225361
167754Smsmith/*
267754Smsmith * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
367754Smsmith * Copyright (C) 1999-2003  Internet Software Consortium.
4117521Snjl *
567754Smsmith * Permission to use, copy, modify, and/or distribute this software for any
667754Smsmith * purpose with or without fee is hereby granted, provided that the above
767754Smsmith * copyright notice and this permission notice appear in all copies.
867754Smsmith *
967754Smsmith * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1067754Smsmith * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1167754Smsmith * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12114237Snjl * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1370243Smsmith * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1467754Smsmith * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1567754Smsmith * PERFORMANCE OF THIS SOFTWARE.
1667754Smsmith */
1767754Smsmith
1867754Smsmith/* $Id: view.c,v 1.178.8.1 2011-03-11 06:47:06 marka Exp $ */
1967754Smsmith
2067754Smsmith/*! \file */
2167754Smsmith
2267754Smsmith#include <config.h>
2367754Smsmith
2467754Smsmith#include <isc/file.h>
2567754Smsmith#include <isc/hash.h>
2667754Smsmith#include <isc/print.h>
2767754Smsmith#include <isc/sha2.h>
2867754Smsmith#include <isc/stats.h>
2967754Smsmith#include <isc/string.h>		/* Required for HP/UX (and others?) */
3067754Smsmith#include <isc/task.h>
3167754Smsmith#include <isc/util.h>
3267754Smsmith
3367754Smsmith#include <dns/acache.h>
3467754Smsmith#include <dns/acl.h>
3567754Smsmith#include <dns/adb.h>
3667754Smsmith#include <dns/cache.h>
3767754Smsmith#include <dns/db.h>
3867754Smsmith#include <dns/dlz.h>
3967754Smsmith#ifdef BIND9
4067754Smsmith#include <dns/dns64.h>
4167754Smsmith#endif
4267754Smsmith#include <dns/dnssec.h>
4367754Smsmith#include <dns/events.h>
4467754Smsmith#include <dns/forward.h>
4567754Smsmith#include <dns/keytable.h>
4667754Smsmith#include <dns/keyvalues.h>
4767754Smsmith#include <dns/master.h>
4867754Smsmith#include <dns/masterdump.h>
4967754Smsmith#include <dns/order.h>
5067754Smsmith#include <dns/peer.h>
5167754Smsmith#include <dns/rbt.h>
5267754Smsmith#include <dns/rdataset.h>
5367754Smsmith#include <dns/request.h>
5467754Smsmith#include <dns/resolver.h>
5567754Smsmith#include <dns/result.h>
5667754Smsmith#include <dns/rpz.h>
5767754Smsmith#include <dns/stats.h>
5867754Smsmith#include <dns/tsig.h>
5967754Smsmith#include <dns/zone.h>
6067754Smsmith#include <dns/zt.h>
6167754Smsmith
6267754Smsmith#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
6367754Smsmith#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
6467754Smsmith#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
6567754Smsmith
6667754Smsmith#define DNS_VIEW_DELONLYHASH 111
6767754Smsmith
6867754Smsmithstatic void resolver_shutdown(isc_task_t *task, isc_event_t *event);
6967754Smsmithstatic void adb_shutdown(isc_task_t *task, isc_event_t *event);
7067754Smsmithstatic void req_shutdown(isc_task_t *task, isc_event_t *event);
7167754Smsmith
7267754Smsmithisc_result_t
7367754Smsmithdns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
7467754Smsmith		const char *name, dns_view_t **viewp)
7567754Smsmith{
7667754Smsmith	dns_view_t *view;
7767754Smsmith	isc_result_t result;
7867754Smsmith
7967754Smsmith	/*
8067754Smsmith	 * Create a view.
8167754Smsmith	 */
8267754Smsmith
8367754Smsmith	REQUIRE(name != NULL);
8467754Smsmith	REQUIRE(viewp != NULL && *viewp == NULL);
8567754Smsmith
8667754Smsmith	view = isc_mem_get(mctx, sizeof(*view));
8767754Smsmith	if (view == NULL)
8867754Smsmith		return (ISC_R_NOMEMORY);
8967754Smsmith	view->name = isc_mem_strdup(mctx, name);
9067754Smsmith	if (view->name == NULL) {
9167754Smsmith		result = ISC_R_NOMEMORY;
9267754Smsmith		goto cleanup_view;
9367754Smsmith	}
9467754Smsmith	result = isc_mutex_init(&view->lock);
9567754Smsmith	if (result != ISC_R_SUCCESS)
9667754Smsmith		goto cleanup_name;
9767754Smsmith
9867754Smsmith#ifdef BIND9
9967754Smsmith	view->zonetable = NULL;
10067754Smsmith	result = dns_zt_create(mctx, rdclass, &view->zonetable);
10167754Smsmith	if (result != ISC_R_SUCCESS) {
10267754Smsmith		UNEXPECTED_ERROR(__FILE__, __LINE__,
10367754Smsmith				 "dns_zt_create() failed: %s",
10467754Smsmith				 isc_result_totext(result));
10567754Smsmith		result = ISC_R_UNEXPECTED;
10667754Smsmith		goto cleanup_mutex;
10767754Smsmith	}
10867754Smsmith#endif
10967754Smsmith	view->secroots_priv = NULL;
11067754Smsmith	view->fwdtable = NULL;
11167754Smsmith	result = dns_fwdtable_create(mctx, &view->fwdtable);
11267754Smsmith	if (result != ISC_R_SUCCESS) {
11367754Smsmith		UNEXPECTED_ERROR(__FILE__, __LINE__,
11467754Smsmith				 "dns_fwdtable_create() failed: %s",
11567754Smsmith				 isc_result_totext(result));
11667754Smsmith		result = ISC_R_UNEXPECTED;
11767754Smsmith		goto cleanup_zt;
11867754Smsmith	}
11967754Smsmith
12067754Smsmith	view->acache = NULL;
12167754Smsmith	view->cache = NULL;
12267754Smsmith	view->cachedb = NULL;
12367754Smsmith	view->dlzdatabase = NULL;
12467754Smsmith	view->hints = NULL;
125117521Snjl	view->resolver = NULL;
12667754Smsmith	view->adb = NULL;
12767754Smsmith	view->requestmgr = NULL;
128102550Siwasaki	view->mctx = mctx;
12967754Smsmith	view->rdclass = rdclass;
13067754Smsmith	view->frozen = ISC_FALSE;
131102550Siwasaki	view->task = NULL;
13291116Smsmith	result = isc_refcount_init(&view->references, 1);
13367754Smsmith	if (result != ISC_R_SUCCESS)
13467754Smsmith		goto cleanup_fwdtable;
13567754Smsmith	view->weakrefs = 0;
13667754Smsmith	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
13767754Smsmith			    DNS_VIEWATTR_REQSHUTDOWN);
13867754Smsmith	view->statickeys = NULL;
13967754Smsmith	view->dynamickeys = NULL;
14067754Smsmith	view->matchclients = NULL;
14167754Smsmith	view->matchdestinations = NULL;
14267754Smsmith	view->matchrecursiveonly = ISC_FALSE;
14367754Smsmith	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
14467754Smsmith	if (result != ISC_R_SUCCESS)
14567754Smsmith		goto cleanup_references;
14667754Smsmith	view->peers = NULL;
14767754Smsmith	view->order = NULL;
14867754Smsmith	view->delonly = NULL;
14967754Smsmith	view->rootdelonly = ISC_FALSE;
15067754Smsmith	view->rootexclude = NULL;
15167754Smsmith	view->resstats = NULL;
15267754Smsmith	view->resquerystats = NULL;
15367754Smsmith	view->cacheshared = ISC_FALSE;
15499679Siwasaki	ISC_LIST_INIT(view->dns64);
15567754Smsmith	view->dns64cnt = 0;
15667754Smsmith
15767754Smsmith	/*
15867754Smsmith	 * Initialize configuration data with default values.
15967754Smsmith	 */
16067754Smsmith	view->recursion = ISC_TRUE;
16167754Smsmith	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
16267754Smsmith	view->additionalfromcache = ISC_TRUE;
16367754Smsmith	view->additionalfromauth = ISC_TRUE;
16467754Smsmith	view->enablednssec = ISC_TRUE;
16567754Smsmith	view->enablevalidation = ISC_TRUE;
16667754Smsmith	view->acceptexpired = ISC_FALSE;
16767754Smsmith	view->minimalresponses = ISC_FALSE;
16867754Smsmith	view->transfer_format = dns_one_answer;
16991116Smsmith	view->cacheacl = NULL;
17067754Smsmith	view->cacheonacl = NULL;
17167754Smsmith	view->queryacl = NULL;
17267754Smsmith	view->queryonacl = NULL;
17367754Smsmith	view->recursionacl = NULL;
17467754Smsmith	view->recursiononacl = NULL;
17567754Smsmith	view->sortlist = NULL;
17667754Smsmith	view->transferacl = NULL;
17767754Smsmith	view->notifyacl = NULL;
17867754Smsmith	view->updateacl = NULL;
17967754Smsmith	view->upfwdacl = NULL;
18067754Smsmith	view->denyansweracl = NULL;
18167754Smsmith	view->answeracl_exclude = NULL;
18267754Smsmith	view->denyanswernames = NULL;
18367754Smsmith	view->answernames_exclude = NULL;
18467754Smsmith	view->requestixfr = ISC_TRUE;
18567754Smsmith	view->provideixfr = ISC_TRUE;
18667754Smsmith	view->maxcachettl = 7 * 24 * 3600;
18767754Smsmith	view->maxncachettl = 3 * 3600;
18867754Smsmith	view->dstport = 53;
18967754Smsmith	view->preferred_glue = 0;
19067754Smsmith	view->flush = ISC_FALSE;
19167754Smsmith	view->dlv = NULL;
19283174Smsmith	view->maxudp = 0;
19367754Smsmith	view->v4_aaaa = dns_v4_aaaa_ok;
19467754Smsmith	view->v4_aaaa_acl = NULL;
19599679Siwasaki	ISC_LIST_INIT(view->rpz_zones);
19667754Smsmith	dns_fixedname_init(&view->dlv_fixed);
19767754Smsmith	view->managed_keys = NULL;
19899679Siwasaki#ifdef BIND9
19967754Smsmith	view->new_zone_file = NULL;
20091116Smsmith	view->new_zone_config = NULL;
20167754Smsmith	view->cfg_destroy = NULL;
20299679Siwasaki
20399679Siwasaki	result = dns_order_create(view->mctx, &view->order);
20499679Siwasaki	if (result != ISC_R_SUCCESS)
20567754Smsmith		goto cleanup_dynkeys;
20667754Smsmith#endif
20767754Smsmith
20867754Smsmith	result = dns_peerlist_new(view->mctx, &view->peers);
20967754Smsmith	if (result != ISC_R_SUCCESS)
21067754Smsmith		goto cleanup_order;
21167754Smsmith
21267754Smsmith	result = dns_aclenv_init(view->mctx, &view->aclenv);
21367754Smsmith	if (result != ISC_R_SUCCESS)
21467754Smsmith		goto cleanup_peerlist;
21567754Smsmith
21667754Smsmith	ISC_LINK_INIT(view, link);
21767754Smsmith	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
21867754Smsmith		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
21967754Smsmith		       view, NULL, NULL, NULL);
22067754Smsmith	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
22167754Smsmith		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
22267754Smsmith		       view, NULL, NULL, NULL);
22367754Smsmith	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
224114237Snjl		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
225114237Snjl		       view, NULL, NULL, NULL);
22667754Smsmith	view->magic = DNS_VIEW_MAGIC;
22767754Smsmith
22867754Smsmith	*viewp = view;
22987031Smsmith
23067754Smsmith	return (ISC_R_SUCCESS);
231114237Snjl
23267754Smsmith cleanup_peerlist:
23367754Smsmith	dns_peerlist_detach(&view->peers);
23467754Smsmith
23567754Smsmith cleanup_order:
23667754Smsmith#ifdef BIND9
23767754Smsmith	dns_order_detach(&view->order);
23867754Smsmith
23967754Smsmith cleanup_dynkeys:
24067754Smsmith#endif
24167754Smsmith	dns_tsigkeyring_detach(&view->dynamickeys);
24267754Smsmith
24367754Smsmith cleanup_references:
24467754Smsmith	isc_refcount_destroy(&view->references);
24567754Smsmith
24691116Smsmith cleanup_fwdtable:
24767754Smsmith	dns_fwdtable_destroy(&view->fwdtable);
24867754Smsmith
24967754Smsmith cleanup_zt:
25067754Smsmith#ifdef BIND9
25167754Smsmith	dns_zt_detach(&view->zonetable);
25267754Smsmith
25367754Smsmith cleanup_mutex:
25467754Smsmith#endif
25567754Smsmith	DESTROYLOCK(&view->lock);
25667754Smsmith
25767754Smsmith cleanup_name:
25867754Smsmith	isc_mem_free(mctx, view->name);
25967754Smsmith
26067754Smsmith cleanup_view:
26167754Smsmith	isc_mem_put(mctx, view, sizeof(*view));
26267754Smsmith
26367754Smsmith	return (result);
26467754Smsmith}
26567754Smsmith
26667754Smsmithstatic inline void
26767754Smsmithdestroy(dns_view_t *view) {
26867754Smsmith#ifdef BIND9
26967754Smsmith	dns_dns64_t *dns64;
27067754Smsmith#endif
27167754Smsmith
27267754Smsmith	REQUIRE(!ISC_LINK_LINKED(view, link));
27367754Smsmith	REQUIRE(isc_refcount_current(&view->references) == 0);
27467754Smsmith	REQUIRE(view->weakrefs == 0);
27567754Smsmith	REQUIRE(RESSHUTDOWN(view));
27667754Smsmith	REQUIRE(ADBSHUTDOWN(view));
27791116Smsmith	REQUIRE(REQSHUTDOWN(view));
27867754Smsmith
27991116Smsmith#ifdef BIND9
28067754Smsmith	if (view->order != NULL)
28191116Smsmith		dns_order_detach(&view->order);
28291116Smsmith#endif
28367754Smsmith	if (view->peers != NULL)
28467754Smsmith		dns_peerlist_detach(&view->peers);
28567754Smsmith
28667754Smsmith	if (view->dynamickeys != NULL) {
28767754Smsmith		isc_result_t result;
28867754Smsmith		char template[20];
28967754Smsmith		char keyfile[20];
29067754Smsmith		FILE *fp = NULL;
29167754Smsmith		int n;
29267754Smsmith
29399679Siwasaki		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
29491116Smsmith			     view->name);
29591116Smsmith		if (n > 0 && (size_t)n < sizeof(keyfile)) {
29691116Smsmith			result = isc_file_mktemplate(keyfile, template,
29767754Smsmith						     sizeof(template));
29867754Smsmith			if (result == ISC_R_SUCCESS)
29967754Smsmith				(void)isc_file_openuniqueprivate(template, &fp);
30067754Smsmith		}
30167754Smsmith		if (fp == NULL)
30267754Smsmith			dns_tsigkeyring_detach(&view->dynamickeys);
30377424Smsmith		else {
30477424Smsmith			result = dns_tsigkeyring_dumpanddetach(
30591116Smsmith							&view->dynamickeys, fp);
30667754Smsmith			if (result == ISC_R_SUCCESS) {
30767754Smsmith				if (fclose(fp) == 0)
30891116Smsmith					result = isc_file_rename(template,
30991116Smsmith								 keyfile);
31091116Smsmith				if (result != ISC_R_SUCCESS)
31191116Smsmith					(void)remove(template);
31267754Smsmith			} else {
31367754Smsmith				(void)fclose(fp);
31467754Smsmith				(void)remove(template);
31567754Smsmith			}
31667754Smsmith		}
31767754Smsmith	}
31877424Smsmith	if (view->statickeys != NULL)
31967754Smsmith		dns_tsigkeyring_detach(&view->statickeys);
32091116Smsmith	if (view->adb != NULL)
32167754Smsmith		dns_adb_detach(&view->adb);
32291116Smsmith	if (view->resolver != NULL)
32391116Smsmith		dns_resolver_detach(&view->resolver);
32491116Smsmith#ifdef BIND9
32591116Smsmith	if (view->acache != NULL) {
32691116Smsmith		if (view->cachedb != NULL)
32767754Smsmith			dns_acache_putdb(view->acache, view->cachedb);
32867754Smsmith		dns_acache_detach(&view->acache);
32967754Smsmith	}
33067754Smsmith	dns_rpz_view_destroy(view);
33167754Smsmith#else
33267754Smsmith	INSIST(view->acache == NULL);
33367754Smsmith	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
33467754Smsmith#endif
33577424Smsmith	if (view->requestmgr != NULL)
33691116Smsmith		dns_requestmgr_detach(&view->requestmgr);
33767754Smsmith	if (view->task != NULL)
33867754Smsmith		isc_task_detach(&view->task);
33967754Smsmith	if (view->hints != NULL)
34067754Smsmith		dns_db_detach(&view->hints);
34167754Smsmith	if (view->dlzdatabase != NULL)
34267754Smsmith		dns_dlzdestroy(&view->dlzdatabase);
34367754Smsmith	if (view->cachedb != NULL)
34467754Smsmith		dns_db_detach(&view->cachedb);
34567754Smsmith	if (view->cache != NULL)
34667754Smsmith		dns_cache_detach(&view->cache);
34767754Smsmith	if (view->matchclients != NULL)
34867754Smsmith		dns_acl_detach(&view->matchclients);
34967754Smsmith	if (view->matchdestinations != NULL)
35067754Smsmith		dns_acl_detach(&view->matchdestinations);
35167754Smsmith	if (view->cacheacl != NULL)
35267754Smsmith		dns_acl_detach(&view->cacheacl);
35367754Smsmith	if (view->cacheonacl != NULL)
35467754Smsmith		dns_acl_detach(&view->cacheonacl);
35567754Smsmith	if (view->queryacl != NULL)
35667754Smsmith		dns_acl_detach(&view->queryacl);
35767754Smsmith	if (view->queryonacl != NULL)
35867754Smsmith		dns_acl_detach(&view->queryonacl);
35967754Smsmith	if (view->recursionacl != NULL)
36069746Smsmith		dns_acl_detach(&view->recursionacl);
36169746Smsmith	if (view->recursiononacl != NULL)
362104470Siwasaki		dns_acl_detach(&view->recursiononacl);
36369746Smsmith	if (view->sortlist != NULL)
36469746Smsmith		dns_acl_detach(&view->sortlist);
36567754Smsmith	if (view->transferacl != NULL)
36667754Smsmith		dns_acl_detach(&view->transferacl);
36767754Smsmith	if (view->notifyacl != NULL)
36867754Smsmith		dns_acl_detach(&view->notifyacl);
36967754Smsmith	if (view->updateacl != NULL)
37067754Smsmith		dns_acl_detach(&view->updateacl);
37177424Smsmith	if (view->upfwdacl != NULL)
37277424Smsmith		dns_acl_detach(&view->upfwdacl);
37367754Smsmith	if (view->denyansweracl != NULL)
37487031Smsmith		dns_acl_detach(&view->denyansweracl);
37587031Smsmith	if (view->v4_aaaa_acl != NULL)
37667754Smsmith		dns_acl_detach(&view->v4_aaaa_acl);
37787031Smsmith	if (view->answeracl_exclude != NULL)
37887031Smsmith		dns_rbt_destroy(&view->answeracl_exclude);
37967754Smsmith	if (view->denyanswernames != NULL)
38087031Smsmith		dns_rbt_destroy(&view->denyanswernames);
38167754Smsmith	if (view->answernames_exclude != NULL)
38267754Smsmith		dns_rbt_destroy(&view->answernames_exclude);
38367754Smsmith	if (view->delonly != NULL) {
38487031Smsmith		dns_name_t *name;
38587031Smsmith		int i;
38667754Smsmith
38767754Smsmith		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
38867754Smsmith			name = ISC_LIST_HEAD(view->delonly[i]);
38967754Smsmith			while (name != NULL) {
39067754Smsmith				ISC_LIST_UNLINK(view->delonly[i], name, link);
39167754Smsmith				dns_name_free(name, view->mctx);
39267754Smsmith				isc_mem_put(view->mctx, name, sizeof(*name));
39367754Smsmith				name = ISC_LIST_HEAD(view->delonly[i]);
39467754Smsmith			}
39567754Smsmith		}
39667754Smsmith		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
39767754Smsmith			    DNS_VIEW_DELONLYHASH);
39867754Smsmith		view->delonly = NULL;
39967754Smsmith	}
40067754Smsmith	if (view->rootexclude != NULL) {
40167754Smsmith		dns_name_t *name;
40267754Smsmith		int i;
40367754Smsmith
40467754Smsmith		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
40567754Smsmith			name = ISC_LIST_HEAD(view->rootexclude[i]);
40667754Smsmith			while (name != NULL) {
40767754Smsmith				ISC_LIST_UNLINK(view->rootexclude[i],
40867754Smsmith						name, link);
40967754Smsmith				dns_name_free(name, view->mctx);
41067754Smsmith				isc_mem_put(view->mctx, name, sizeof(*name));
41183174Smsmith				name = ISC_LIST_HEAD(view->rootexclude[i]);
41267754Smsmith			}
41367754Smsmith		}
41467754Smsmith		isc_mem_put(view->mctx, view->rootexclude,
41567754Smsmith			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
41667754Smsmith		view->rootexclude = NULL;
41767754Smsmith	}
41867754Smsmith	if (view->resstats != NULL)
41967754Smsmith		isc_stats_detach(&view->resstats);
42067754Smsmith	if (view->resquerystats != NULL)
42167754Smsmith		dns_stats_detach(&view->resquerystats);
42267754Smsmith	if (view->secroots_priv != NULL)
42367754Smsmith		dns_keytable_detach(&view->secroots_priv);
42467754Smsmith#ifdef BIND9
42567754Smsmith	for (dns64 = ISC_LIST_HEAD(view->dns64);
42667754Smsmith	     dns64 != NULL;
42767754Smsmith	     dns64 = ISC_LIST_HEAD(view->dns64)) {
42867754Smsmith		dns_dns64_unlink(&view->dns64, dns64);
42967754Smsmith		dns_dns64_destroy(&dns64);
43067754Smsmith	}
43187031Smsmith	if (view->managed_keys != NULL)
43267754Smsmith		dns_zone_detach(&view->managed_keys);
43387031Smsmith	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
43467754Smsmith#endif
43567754Smsmith	dns_fwdtable_destroy(&view->fwdtable);
43699679Siwasaki	dns_aclenv_destroy(&view->aclenv);
43769746Smsmith	DESTROYLOCK(&view->lock);
43867754Smsmith	isc_refcount_destroy(&view->references);
43967754Smsmith	isc_mem_free(view->mctx, view->name);
44067754Smsmith	isc_mem_put(view->mctx, view, sizeof(*view));
44199679Siwasaki}
44267754Smsmith
44399679Siwasaki/*
44467754Smsmith * Return true iff 'view' may be freed.
44567754Smsmith * The caller must be holding the view lock.
44667754Smsmith */
44767754Smsmithstatic isc_boolean_t
44867754Smsmithall_done(dns_view_t *view) {
44967754Smsmith
45067754Smsmith	if (isc_refcount_current(&view->references) == 0 &&
45167754Smsmith	    view->weakrefs == 0 &&
45267754Smsmith	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
45367754Smsmith		return (ISC_TRUE);
45467754Smsmith
45567754Smsmith	return (ISC_FALSE);
45667754Smsmith}
45767754Smsmith
45867754Smsmithvoid
45967754Smsmithdns_view_attach(dns_view_t *source, dns_view_t **targetp) {
46067754Smsmith
46167754Smsmith	REQUIRE(DNS_VIEW_VALID(source));
46267754Smsmith	REQUIRE(targetp != NULL && *targetp == NULL);
46399679Siwasaki
46485756Smsmith	isc_refcount_increment(&source->references, NULL);
46567754Smsmith
46685756Smsmith	*targetp = source;
46767754Smsmith}
46867754Smsmith
46967754Smsmithstatic void
47067754Smsmithview_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
47167754Smsmith	dns_view_t *view;
47267754Smsmith	unsigned int refs;
47367754Smsmith	isc_boolean_t done = ISC_FALSE;
47467754Smsmith
47585756Smsmith	REQUIRE(viewp != NULL);
47685756Smsmith	view = *viewp;
47785756Smsmith	REQUIRE(DNS_VIEW_VALID(view));
47885756Smsmith
47985756Smsmith	if (flush)
48067754Smsmith		view->flush = ISC_TRUE;
48167754Smsmith	isc_refcount_decrement(&view->references, &refs);
48267754Smsmith	if (refs == 0) {
48367754Smsmith		LOCK(&view->lock);
48467754Smsmith		if (!RESSHUTDOWN(view))
48567754Smsmith			dns_resolver_shutdown(view->resolver);
48667754Smsmith		if (!ADBSHUTDOWN(view))
48767754Smsmith			dns_adb_shutdown(view->adb);
48867754Smsmith		if (!REQSHUTDOWN(view))
48967754Smsmith			dns_requestmgr_shutdown(view->requestmgr);
49067754Smsmith#ifdef BIND9
49167754Smsmith		if (view->acache != NULL)
49267754Smsmith			dns_acache_shutdown(view->acache);
49369746Smsmith		if (view->flush)
49467754Smsmith			dns_zt_flushanddetach(&view->zonetable);
49567754Smsmith		else
49669746Smsmith			dns_zt_detach(&view->zonetable);
49767754Smsmith		if (view->managed_keys != NULL) {
49867754Smsmith			if (view->flush)
49967754Smsmith				dns_zone_flush(view->managed_keys);
50067754Smsmith			dns_zone_detach(&view->managed_keys);
50167754Smsmith		}
50267754Smsmith#endif
50367754Smsmith		done = all_done(view);
50467754Smsmith		UNLOCK(&view->lock);
50567754Smsmith	}
50667754Smsmith
50767754Smsmith	*viewp = NULL;
50867754Smsmith
50967754Smsmith	if (done)
51067754Smsmith		destroy(view);
51167754Smsmith}
51267754Smsmith
51367754Smsmithvoid
51467754Smsmithdns_view_flushanddetach(dns_view_t **viewp) {
51567754Smsmith	view_flushanddetach(viewp, ISC_TRUE);
51667754Smsmith}
51767754Smsmith
51867754Smsmithvoid
51967754Smsmithdns_view_detach(dns_view_t **viewp) {
52067754Smsmith	view_flushanddetach(viewp, ISC_FALSE);
52167754Smsmith}
52267754Smsmith
52367754Smsmith#ifdef BIND9
52467754Smsmithstatic isc_result_t
52567754Smsmithdialup(dns_zone_t *zone, void *dummy) {
526117521Snjl	UNUSED(dummy);
52767754Smsmith	dns_zone_dialup(zone);
52867754Smsmith	return (ISC_R_SUCCESS);
52967754Smsmith}
53067754Smsmith
53167754Smsmithvoid
53267754Smsmithdns_view_dialup(dns_view_t *view) {
53367754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
53467754Smsmith	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
53567754Smsmith}
53667754Smsmith#endif
53767754Smsmith
53867754Smsmithvoid
53967754Smsmithdns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
54067754Smsmith
54167754Smsmith	REQUIRE(DNS_VIEW_VALID(source));
54267754Smsmith	REQUIRE(targetp != NULL && *targetp == NULL);
54367754Smsmith
54467754Smsmith	LOCK(&source->lock);
54567754Smsmith	source->weakrefs++;
54667754Smsmith	UNLOCK(&source->lock);
54767754Smsmith
54867754Smsmith	*targetp = source;
54967754Smsmith}
55067754Smsmith
55167754Smsmithvoid
55267754Smsmithdns_view_weakdetach(dns_view_t **viewp) {
55367754Smsmith	dns_view_t *view;
55467754Smsmith	isc_boolean_t done = ISC_FALSE;
555117521Snjl
55667754Smsmith	REQUIRE(viewp != NULL);
55767754Smsmith	view = *viewp;
55867754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
55967754Smsmith
56067754Smsmith	LOCK(&view->lock);
56167754Smsmith
56267754Smsmith	INSIST(view->weakrefs > 0);
56367754Smsmith	view->weakrefs--;
56467754Smsmith	done = all_done(view);
56567754Smsmith
56667754Smsmith	UNLOCK(&view->lock);
56767754Smsmith
56867754Smsmith	*viewp = NULL;
56967754Smsmith
57067754Smsmith	if (done)
57167754Smsmith		destroy(view);
57267754Smsmith}
57367754Smsmith
57467754Smsmithstatic void
57567754Smsmithresolver_shutdown(isc_task_t *task, isc_event_t *event) {
57667754Smsmith	dns_view_t *view = event->ev_arg;
57769746Smsmith	isc_boolean_t done;
57867754Smsmith
57967754Smsmith	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
58067754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
58167754Smsmith	REQUIRE(view->task == task);
58267754Smsmith
58367754Smsmith	UNUSED(task);
58467754Smsmith
58567754Smsmith	LOCK(&view->lock);
58667754Smsmith
58767754Smsmith	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
58867754Smsmith	done = all_done(view);
58967754Smsmith
59067754Smsmith	UNLOCK(&view->lock);
59169746Smsmith
59269746Smsmith	isc_event_free(&event);
59369746Smsmith
59469746Smsmith	if (done)
59567754Smsmith		destroy(view);
59687031Smsmith}
59799679Siwasaki
59869746Smsmithstatic void
59969746Smsmithadb_shutdown(isc_task_t *task, isc_event_t *event) {
60067754Smsmith	dns_view_t *view = event->ev_arg;
60169746Smsmith	isc_boolean_t done;
60267754Smsmith
603117521Snjl	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
60467754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
60567754Smsmith	REQUIRE(view->task == task);
60667754Smsmith
60767754Smsmith	UNUSED(task);
60867754Smsmith
60967754Smsmith	LOCK(&view->lock);
61067754Smsmith
61167754Smsmith	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
61267754Smsmith	done = all_done(view);
61367754Smsmith
61467754Smsmith	UNLOCK(&view->lock);
61567754Smsmith
61667754Smsmith	isc_event_free(&event);
61767754Smsmith
61867754Smsmith	if (done)
61967754Smsmith		destroy(view);
62067754Smsmith}
62167754Smsmith
62267754Smsmithstatic void
62367754Smsmithreq_shutdown(isc_task_t *task, isc_event_t *event) {
62467754Smsmith	dns_view_t *view = event->ev_arg;
62567754Smsmith	isc_boolean_t done;
62667754Smsmith
62767754Smsmith	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
62867754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
62967754Smsmith	REQUIRE(view->task == task);
63067754Smsmith
63167754Smsmith	UNUSED(task);
63267754Smsmith
63367754Smsmith	LOCK(&view->lock);
63469450Smsmith
63567754Smsmith	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
63667754Smsmith	done = all_done(view);
63799679Siwasaki
63867754Smsmith	UNLOCK(&view->lock);
63969450Smsmith
64067754Smsmith	isc_event_free(&event);
64199679Siwasaki
64267754Smsmith	if (done)
64367754Smsmith		destroy(view);
64467754Smsmith}
64567754Smsmith
64667754Smsmithisc_result_t
64767754Smsmithdns_view_createresolver(dns_view_t *view,
64867754Smsmith			isc_taskmgr_t *taskmgr, unsigned int ntasks,
64967754Smsmith			isc_socketmgr_t *socketmgr,
650117521Snjl			isc_timermgr_t *timermgr,
651117521Snjl			unsigned int options,
652117521Snjl			dns_dispatchmgr_t *dispatchmgr,
653117521Snjl			dns_dispatch_t *dispatchv4,
654117521Snjl			dns_dispatch_t *dispatchv6)
655117521Snjl{
656117521Snjl	isc_result_t result;
657117521Snjl	isc_event_t *event;
658117521Snjl	isc_mem_t *mctx = NULL;
659117521Snjl
660117521Snjl	REQUIRE(DNS_VIEW_VALID(view));
661117521Snjl	REQUIRE(!view->frozen);
662117521Snjl	REQUIRE(view->resolver == NULL);
663117521Snjl
664117521Snjl	result = isc_task_create(taskmgr, 0, &view->task);
665117521Snjl	if (result != ISC_R_SUCCESS)
666117521Snjl		return (result);
667117521Snjl	isc_task_setname(view->task, "view", view);
668117521Snjl
669117521Snjl	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
670117521Snjl				     timermgr, options, dispatchmgr,
671117521Snjl				     dispatchv4, dispatchv6,
672117521Snjl				     &view->resolver);
673117521Snjl	if (result != ISC_R_SUCCESS) {
674117521Snjl		isc_task_detach(&view->task);
675117521Snjl		return (result);
676117521Snjl	}
677117521Snjl	event = &view->resevent;
678117521Snjl	dns_resolver_whenshutdown(view->resolver, view->task, &event);
679117521Snjl	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
680117521Snjl
681117521Snjl	result = isc_mem_create(0, 0, &mctx);
682117521Snjl	if (result != ISC_R_SUCCESS) {
683117521Snjl		dns_resolver_shutdown(view->resolver);
684117521Snjl		return (result);
685117521Snjl	}
686117521Snjl
687117521Snjl	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
688117521Snjl	isc_mem_setname(mctx, "ADB", NULL);
689117521Snjl	isc_mem_detach(&mctx);
690117521Snjl	if (result != ISC_R_SUCCESS) {
691117521Snjl		dns_resolver_shutdown(view->resolver);
692117521Snjl		return (result);
693117521Snjl	}
694117521Snjl	event = &view->adbevent;
695117521Snjl	dns_adb_whenshutdown(view->adb, view->task, &event);
696117521Snjl	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
697117521Snjl
698117521Snjl	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
699117521Snjl				      dns_resolver_taskmgr(view->resolver),
700117521Snjl				      dns_resolver_dispatchmgr(view->resolver),
701117521Snjl				      dns_resolver_dispatchv4(view->resolver),
702117521Snjl				      dns_resolver_dispatchv6(view->resolver),
70367754Smsmith				      &view->requestmgr);
70467754Smsmith	if (result != ISC_R_SUCCESS) {
70567754Smsmith		dns_adb_shutdown(view->adb);
70667754Smsmith		dns_resolver_shutdown(view->resolver);
70767754Smsmith		return (result);
70867754Smsmith	}
70967754Smsmith	event = &view->reqevent;
71067754Smsmith	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
71167754Smsmith	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
71291116Smsmith
71391116Smsmith	return (ISC_R_SUCCESS);
71491116Smsmith}
71591116Smsmith
71667754Smsmithvoid
71767754Smsmithdns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
71867754Smsmith	dns_view_setcache2(view, cache, ISC_FALSE);
71967754Smsmith}
72067754Smsmith
72167754Smsmithvoid
72267754Smsmithdns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
72367754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
72491116Smsmith	REQUIRE(!view->frozen);
72591116Smsmith
72667754Smsmith	view->cacheshared = shared;
72767754Smsmith	if (view->cache != NULL) {
72867754Smsmith#ifdef BIND9
72967754Smsmith		if (view->acache != NULL)
73067754Smsmith			dns_acache_putdb(view->acache, view->cachedb);
73167754Smsmith#endif
732117521Snjl		dns_db_detach(&view->cachedb);
73367754Smsmith		dns_cache_detach(&view->cache);
73467754Smsmith	}
73567754Smsmith	dns_cache_attach(cache, &view->cache);
73667754Smsmith	dns_cache_attachdb(cache, &view->cachedb);
73767754Smsmith	INSIST(DNS_DB_VALID(view->cachedb));
73867754Smsmith
73967754Smsmith#ifdef BIND9
74067754Smsmith	if (view->acache != NULL)
74167754Smsmith		dns_acache_setdb(view->acache, view->cachedb);
74267754Smsmith#endif
74367754Smsmith}
74467754Smsmith
74567754Smsmithisc_boolean_t
74667754Smsmithdns_view_iscacheshared(dns_view_t *view) {
74767754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
74867754Smsmith
74967754Smsmith	return (view->cacheshared);
75067754Smsmith}
75167754Smsmith
75267754Smsmithvoid
75367754Smsmithdns_view_sethints(dns_view_t *view, dns_db_t *hints) {
75467754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
75567754Smsmith	REQUIRE(!view->frozen);
75667754Smsmith	REQUIRE(view->hints == NULL);
75767754Smsmith	REQUIRE(dns_db_iszone(hints));
75867754Smsmith
75967754Smsmith	dns_db_attach(hints, &view->hints);
76067754Smsmith}
76167754Smsmith
762117521Snjlvoid
76367754Smsmithdns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
76467754Smsmith	REQUIRE(DNS_VIEW_VALID(view));
765114237Snjl	REQUIRE(ring != NULL);
766114237Snjl	if (view->statickeys != NULL)
767114237Snjl		dns_tsigkeyring_detach(&view->statickeys);
768114237Snjl	dns_tsigkeyring_attach(ring, &view->statickeys);
769114237Snjl}
770114237Snjl
771114237Snjlvoid
772114237Snjldns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
773114237Snjl	REQUIRE(DNS_VIEW_VALID(view));
774114237Snjl	REQUIRE(ring != NULL);
775114237Snjl	if (view->dynamickeys != NULL)
776114237Snjl		dns_tsigkeyring_detach(&view->dynamickeys);
777114237Snjl	dns_tsigkeyring_attach(ring, &view->dynamickeys);
778114237Snjl}
779114237Snjl
780114237Snjlvoid
781114237Snjldns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
782117521Snjl	REQUIRE(DNS_VIEW_VALID(view));
783114237Snjl	REQUIRE(ringp != NULL && *ringp == NULL);
784114237Snjl	if (view->dynamickeys != NULL)
785114237Snjl		dns_tsigkeyring_attach(view->dynamickeys, ringp);
786117521Snjl}
787117521Snjl
788114237Snjlvoid
789117521Snjldns_view_restorekeyring(dns_view_t *view) {
790117521Snjl	FILE *fp;
791117521Snjl	char keyfile[20];
792117521Snjl	int n;
793117521Snjl
794117521Snjl	REQUIRE(DNS_VIEW_VALID(view));
795117521Snjl
796117521Snjl	if (view->dynamickeys != NULL) {
797117521Snjl		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
798117521Snjl			     view->name);
799114237Snjl		if (n > 0 && (size_t)n < sizeof(keyfile)) {
800117521Snjl			fp = fopen(keyfile, "r");
801117521Snjl			if (fp != NULL) {
802117521Snjl				dns_keyring_restore(view->dynamickeys, fp);
803117521Snjl				(void)fclose(fp);
804114237Snjl			}
805114237Snjl		}
806114237Snjl	}
807114237Snjl}
808102550Siwasaki
80967754Smsmithvoid
810dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
811	REQUIRE(DNS_VIEW_VALID(view));
812	view->dstport = dstport;
813}
814
815void
816dns_view_freeze(dns_view_t *view) {
817	REQUIRE(DNS_VIEW_VALID(view));
818	REQUIRE(!view->frozen);
819
820	if (view->resolver != NULL) {
821		INSIST(view->cachedb != NULL);
822		dns_resolver_freeze(view->resolver);
823	}
824	view->frozen = ISC_TRUE;
825}
826
827#ifdef BIND9
828void
829dns_view_thaw(dns_view_t *view) {
830	REQUIRE(DNS_VIEW_VALID(view));
831	REQUIRE(view->frozen);
832
833	view->frozen = ISC_FALSE;
834}
835
836isc_result_t
837dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
838	isc_result_t result;
839
840	REQUIRE(DNS_VIEW_VALID(view));
841	REQUIRE(!view->frozen);
842
843	result = dns_zt_mount(view->zonetable, zone);
844
845	return (result);
846}
847#endif
848
849#ifdef BIND9
850isc_result_t
851dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
852	isc_result_t result;
853
854	REQUIRE(DNS_VIEW_VALID(view));
855
856	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
857	if (result == DNS_R_PARTIALMATCH) {
858		dns_zone_detach(zonep);
859		result = ISC_R_NOTFOUND;
860	}
861
862	return (result);
863}
864#endif
865
866isc_result_t
867dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
868	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
869	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
870	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
871	return (dns_view_find2(view, name, type, now, options, use_hints,
872			       ISC_FALSE, dbp, nodep, foundname, rdataset,
873			       sigrdataset));
874}
875
876isc_result_t
877dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
878	       isc_stdtime_t now, unsigned int options,
879	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
880	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
881	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
882{
883	isc_result_t result;
884	dns_db_t *db, *zdb;
885	dns_dbnode_t *node, *znode;
886	isc_boolean_t is_cache, is_staticstub_zone;
887	dns_rdataset_t zrdataset, zsigrdataset;
888	dns_zone_t *zone;
889
890#ifndef BIND9
891	UNUSED(use_hints);
892	UNUSED(use_static_stub);
893#endif
894
895	/*
896	 * Find an rdataset whose owner name is 'name', and whose type is
897	 * 'type'.
898	 */
899
900	REQUIRE(DNS_VIEW_VALID(view));
901	REQUIRE(view->frozen);
902	REQUIRE(type != dns_rdatatype_rrsig);
903	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
904	REQUIRE(nodep == NULL || *nodep == NULL);
905
906	/*
907	 * Initialize.
908	 */
909	dns_rdataset_init(&zrdataset);
910	dns_rdataset_init(&zsigrdataset);
911	zdb = NULL;
912	znode = NULL;
913
914	/*
915	 * Find a database to answer the query.
916	 */
917	zone = NULL;
918	db = NULL;
919	node = NULL;
920	is_staticstub_zone = ISC_FALSE;
921#ifdef BIND9
922	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
923	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
924	    !use_static_stub) {
925		result = ISC_R_NOTFOUND;
926	}
927	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
928		result = dns_zone_getdb(zone, &db);
929		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
930			dns_db_attach(view->cachedb, &db);
931		else if (result != ISC_R_SUCCESS)
932			goto cleanup;
933		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
934		    dns_name_equal(name, dns_zone_getorigin(zone))) {
935			is_staticstub_zone = ISC_TRUE;
936		}
937	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
938		dns_db_attach(view->cachedb, &db);
939#else
940	result = ISC_R_NOTFOUND;
941	if (view->cachedb != NULL)
942		dns_db_attach(view->cachedb, &db);
943#endif /* BIND9 */
944	else
945		goto cleanup;
946
947	is_cache = dns_db_iscache(db);
948
949 db_find:
950	/*
951	 * Now look for an answer in the database.
952	 */
953	result = dns_db_find(db, name, NULL, type, options,
954			     now, &node, foundname, rdataset, sigrdataset);
955
956	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
957		if (dns_rdataset_isassociated(rdataset))
958			dns_rdataset_disassociate(rdataset);
959		if (sigrdataset != NULL &&
960		    dns_rdataset_isassociated(sigrdataset))
961			dns_rdataset_disassociate(sigrdataset);
962		if (node != NULL)
963			dns_db_detachnode(db, &node);
964		if (!is_cache) {
965			dns_db_detach(&db);
966			if (view->cachedb != NULL && !is_staticstub_zone) {
967				/*
968				 * Either the answer is in the cache, or we
969				 * don't know it.
970				 * Note that if the result comes from a
971				 * static-stub zone we stop the search here
972				 * (see the function description in view.h).
973				 */
974				is_cache = ISC_TRUE;
975				dns_db_attach(view->cachedb, &db);
976				goto db_find;
977			}
978		} else {
979			/*
980			 * We don't have the data in the cache.  If we've got
981			 * glue from the zone, use it.
982			 */
983			if (dns_rdataset_isassociated(&zrdataset)) {
984				dns_rdataset_clone(&zrdataset, rdataset);
985				if (sigrdataset != NULL &&
986				    dns_rdataset_isassociated(&zsigrdataset))
987					dns_rdataset_clone(&zsigrdataset,
988							   sigrdataset);
989				result = DNS_R_GLUE;
990				if (db != NULL)
991					dns_db_detach(&db);
992				dns_db_attach(zdb, &db);
993				dns_db_attachnode(db, znode, &node);
994				goto cleanup;
995			}
996		}
997		/*
998		 * We don't know the answer.
999		 */
1000		result = ISC_R_NOTFOUND;
1001	} else if (result == DNS_R_GLUE) {
1002		if (view->cachedb != NULL && !is_staticstub_zone) {
1003			/*
1004			 * We found an answer, but the cache may be better.
1005			 * Remember what we've got and go look in the cache.
1006			 */
1007			is_cache = ISC_TRUE;
1008			dns_rdataset_clone(rdataset, &zrdataset);
1009			dns_rdataset_disassociate(rdataset);
1010			if (sigrdataset != NULL &&
1011			    dns_rdataset_isassociated(sigrdataset)) {
1012				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1013				dns_rdataset_disassociate(sigrdataset);
1014			}
1015			dns_db_attach(db, &zdb);
1016			dns_db_attachnode(zdb, node, &znode);
1017			dns_db_detachnode(db, &node);
1018			dns_db_detach(&db);
1019			dns_db_attach(view->cachedb, &db);
1020			goto db_find;
1021		}
1022		/*
1023		 * Otherwise, the glue is the best answer.
1024		 */
1025		result = ISC_R_SUCCESS;
1026	}
1027
1028#ifdef BIND9
1029	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1030		if (dns_rdataset_isassociated(rdataset))
1031			dns_rdataset_disassociate(rdataset);
1032		if (sigrdataset != NULL &&
1033		    dns_rdataset_isassociated(sigrdataset))
1034			dns_rdataset_disassociate(sigrdataset);
1035		if (db != NULL) {
1036			if (node != NULL)
1037				dns_db_detachnode(db, &node);
1038			dns_db_detach(&db);
1039		}
1040		result = dns_db_find(view->hints, name, NULL, type, options,
1041				     now, &node, foundname,
1042				     rdataset, sigrdataset);
1043		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1044			/*
1045			 * We just used a hint.  Let the resolver know it
1046			 * should consider priming.
1047			 */
1048			dns_resolver_prime(view->resolver);
1049			dns_db_attach(view->hints, &db);
1050			result = DNS_R_HINT;
1051		} else if (result == DNS_R_NXRRSET) {
1052			dns_db_attach(view->hints, &db);
1053			result = DNS_R_HINTNXRRSET;
1054		} else if (result == DNS_R_NXDOMAIN)
1055			result = ISC_R_NOTFOUND;
1056
1057		/*
1058		 * Cleanup if non-standard hints are used.
1059		 */
1060		if (db == NULL && node != NULL)
1061			dns_db_detachnode(view->hints, &node);
1062	}
1063#endif /* BIND9 */
1064
1065 cleanup:
1066	if (dns_rdataset_isassociated(&zrdataset)) {
1067		dns_rdataset_disassociate(&zrdataset);
1068		if (dns_rdataset_isassociated(&zsigrdataset))
1069			dns_rdataset_disassociate(&zsigrdataset);
1070	}
1071
1072	if (zdb != NULL) {
1073		if (znode != NULL)
1074			dns_db_detachnode(zdb, &znode);
1075		dns_db_detach(&zdb);
1076	}
1077
1078	if (db != NULL) {
1079		if (node != NULL) {
1080			if (nodep != NULL)
1081				*nodep = node;
1082			else
1083				dns_db_detachnode(db, &node);
1084		}
1085		if (dbp != NULL)
1086			*dbp = db;
1087		else
1088			dns_db_detach(&db);
1089	} else
1090		INSIST(node == NULL);
1091
1092#ifdef BIND9
1093	if (zone != NULL)
1094		dns_zone_detach(&zone);
1095#endif
1096
1097	return (result);
1098}
1099
1100isc_result_t
1101dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1102		    isc_stdtime_t now, unsigned int options,
1103		    isc_boolean_t use_hints,
1104		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1105{
1106	isc_result_t result;
1107	dns_fixedname_t foundname;
1108
1109	dns_fixedname_init(&foundname);
1110	result = dns_view_find(view, name, type, now, options, use_hints,
1111			       NULL, NULL, dns_fixedname_name(&foundname),
1112			       rdataset, sigrdataset);
1113	if (result == DNS_R_NXDOMAIN) {
1114		/*
1115		 * The rdataset and sigrdataset of the relevant NSEC record
1116		 * may be returned, but the caller cannot use them because
1117		 * foundname is not returned by this simplified API.  We
1118		 * disassociate them here to prevent any misuse by the caller.
1119		 */
1120		if (dns_rdataset_isassociated(rdataset))
1121			dns_rdataset_disassociate(rdataset);
1122		if (sigrdataset != NULL &&
1123		    dns_rdataset_isassociated(sigrdataset))
1124			dns_rdataset_disassociate(sigrdataset);
1125	} else if (result != ISC_R_SUCCESS &&
1126		   result != DNS_R_GLUE &&
1127		   result != DNS_R_HINT &&
1128		   result != DNS_R_NCACHENXDOMAIN &&
1129		   result != DNS_R_NCACHENXRRSET &&
1130		   result != DNS_R_NXRRSET &&
1131		   result != DNS_R_HINTNXRRSET &&
1132		   result != ISC_R_NOTFOUND) {
1133		if (dns_rdataset_isassociated(rdataset))
1134			dns_rdataset_disassociate(rdataset);
1135		if (sigrdataset != NULL &&
1136		    dns_rdataset_isassociated(sigrdataset))
1137			dns_rdataset_disassociate(sigrdataset);
1138		result = ISC_R_NOTFOUND;
1139	}
1140
1141	return (result);
1142}
1143
1144isc_result_t
1145dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1146		     isc_stdtime_t now, unsigned int options,
1147		     isc_boolean_t use_hints,
1148		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1149{
1150	return(dns_view_findzonecut2(view, name, fname, now, options,
1151				     use_hints, ISC_TRUE,
1152				     rdataset, sigrdataset));
1153}
1154
1155isc_result_t
1156dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1157		      isc_stdtime_t now, unsigned int options,
1158		      isc_boolean_t use_hints,	isc_boolean_t use_cache,
1159		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1160{
1161	isc_result_t result;
1162	dns_db_t *db;
1163	isc_boolean_t is_cache, use_zone, try_hints;
1164	dns_zone_t *zone;
1165	dns_name_t *zfname;
1166	dns_rdataset_t zrdataset, zsigrdataset;
1167	dns_fixedname_t zfixedname;
1168
1169	REQUIRE(DNS_VIEW_VALID(view));
1170	REQUIRE(view->frozen);
1171
1172	db = NULL;
1173	zone = NULL;
1174	use_zone = ISC_FALSE;
1175	try_hints = ISC_FALSE;
1176	zfname = NULL;
1177
1178	/*
1179	 * Initialize.
1180	 */
1181	dns_fixedname_init(&zfixedname);
1182	dns_rdataset_init(&zrdataset);
1183	dns_rdataset_init(&zsigrdataset);
1184
1185	/*
1186	 * Find the right database.
1187	 */
1188#ifdef BIND9
1189	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1190	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1191		result = dns_zone_getdb(zone, &db);
1192#else
1193	result = ISC_R_NOTFOUND;
1194#endif
1195	if (result == ISC_R_NOTFOUND) {
1196		/*
1197		 * We're not directly authoritative for this query name, nor
1198		 * is it a subdomain of any zone for which we're
1199		 * authoritative.
1200		 */
1201		if (use_cache && view->cachedb != NULL) {
1202			/*
1203			 * We have a cache; try it.
1204			 */
1205			dns_db_attach(view->cachedb, &db);
1206		} else {
1207			/*
1208			 * Maybe we have hints...
1209			 */
1210			try_hints = ISC_TRUE;
1211			goto finish;
1212		}
1213	} else if (result != ISC_R_SUCCESS) {
1214		/*
1215		 * Something is broken.
1216		 */
1217		goto cleanup;
1218	}
1219	is_cache = dns_db_iscache(db);
1220
1221 db_find:
1222	/*
1223	 * Look for the zonecut.
1224	 */
1225	if (!is_cache) {
1226		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1227				     now, NULL, fname, rdataset, sigrdataset);
1228		if (result == DNS_R_DELEGATION)
1229			result = ISC_R_SUCCESS;
1230		else if (result != ISC_R_SUCCESS)
1231			goto cleanup;
1232		if (use_cache && view->cachedb != NULL && db != view->hints) {
1233			/*
1234			 * We found an answer, but the cache may be better.
1235			 */
1236			zfname = dns_fixedname_name(&zfixedname);
1237			result = dns_name_copy(fname, zfname, NULL);
1238			if (result != ISC_R_SUCCESS)
1239				goto cleanup;
1240			dns_rdataset_clone(rdataset, &zrdataset);
1241			dns_rdataset_disassociate(rdataset);
1242			if (sigrdataset != NULL &&
1243			    dns_rdataset_isassociated(sigrdataset)) {
1244				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1245				dns_rdataset_disassociate(sigrdataset);
1246			}
1247			dns_db_detach(&db);
1248			dns_db_attach(view->cachedb, &db);
1249			is_cache = ISC_TRUE;
1250			goto db_find;
1251		}
1252	} else {
1253		result = dns_db_findzonecut(db, name, options, now, NULL,
1254					    fname, rdataset, sigrdataset);
1255		if (result == ISC_R_SUCCESS) {
1256			if (zfname != NULL &&
1257			    (!dns_name_issubdomain(fname, zfname) ||
1258			     (dns_zone_staticstub &&
1259			      dns_name_equal(fname, zfname)))) {
1260				/*
1261				 * We found a zonecut in the cache, but our
1262				 * zone delegation is better.
1263				 */
1264				use_zone = ISC_TRUE;
1265			}
1266		} else if (result == ISC_R_NOTFOUND) {
1267			if (zfname != NULL) {
1268				/*
1269				 * We didn't find anything in the cache, but we
1270				 * have a zone delegation, so use it.
1271				 */
1272				use_zone = ISC_TRUE;
1273			} else {
1274				/*
1275				 * Maybe we have hints...
1276				 */
1277				try_hints = ISC_TRUE;
1278			}
1279		} else {
1280			/*
1281			 * Something bad happened.
1282			 */
1283			goto cleanup;
1284		}
1285	}
1286
1287 finish:
1288	if (use_zone) {
1289		if (dns_rdataset_isassociated(rdataset)) {
1290			dns_rdataset_disassociate(rdataset);
1291			if (sigrdataset != NULL &&
1292			    dns_rdataset_isassociated(sigrdataset))
1293				dns_rdataset_disassociate(sigrdataset);
1294		}
1295		result = dns_name_copy(zfname, fname, NULL);
1296		if (result != ISC_R_SUCCESS)
1297			goto cleanup;
1298		dns_rdataset_clone(&zrdataset, rdataset);
1299		if (sigrdataset != NULL &&
1300		    dns_rdataset_isassociated(&zrdataset))
1301			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1302	} else if (try_hints && use_hints && view->hints != NULL) {
1303		/*
1304		 * We've found nothing so far, but we have hints.
1305		 */
1306		result = dns_db_find(view->hints, dns_rootname, NULL,
1307				     dns_rdatatype_ns, 0, now, NULL, fname,
1308				     rdataset, NULL);
1309		if (result != ISC_R_SUCCESS) {
1310			/*
1311			 * We can't even find the hints for the root
1312			 * nameservers!
1313			 */
1314			if (dns_rdataset_isassociated(rdataset))
1315				dns_rdataset_disassociate(rdataset);
1316			result = ISC_R_NOTFOUND;
1317		}
1318	}
1319
1320 cleanup:
1321	if (dns_rdataset_isassociated(&zrdataset)) {
1322		dns_rdataset_disassociate(&zrdataset);
1323		if (dns_rdataset_isassociated(&zsigrdataset))
1324			dns_rdataset_disassociate(&zsigrdataset);
1325	}
1326	if (db != NULL)
1327		dns_db_detach(&db);
1328#ifdef BIND9
1329	if (zone != NULL)
1330		dns_zone_detach(&zone);
1331#endif
1332
1333	return (result);
1334}
1335
1336isc_result_t
1337dns_viewlist_find(dns_viewlist_t *list, const char *name,
1338		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1339{
1340	dns_view_t *view;
1341
1342	REQUIRE(list != NULL);
1343
1344	for (view = ISC_LIST_HEAD(*list);
1345	     view != NULL;
1346	     view = ISC_LIST_NEXT(view, link)) {
1347		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1348			break;
1349	}
1350	if (view == NULL)
1351		return (ISC_R_NOTFOUND);
1352
1353	dns_view_attach(view, viewp);
1354
1355	return (ISC_R_SUCCESS);
1356}
1357
1358#ifdef BIND9
1359isc_result_t
1360dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1361		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1362		      dns_zone_t **zonep)
1363{
1364	dns_view_t *view;
1365	isc_result_t result;
1366	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1367	dns_zone_t **zp = NULL;;
1368
1369	REQUIRE(list != NULL);
1370	for (view = ISC_LIST_HEAD(*list);
1371	     view != NULL;
1372	     view = ISC_LIST_NEXT(view, link)) {
1373		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1374			continue;
1375
1376		/*
1377		 * If the zone is defined in more than one view,
1378		 * treat it as not found.
1379		 */
1380		zp = (zone1 == NULL) ? &zone1 : &zone2;
1381		result = dns_zt_find(view->zonetable, name, 0, NULL, zp);
1382		INSIST(result == ISC_R_SUCCESS ||
1383		       result == ISC_R_NOTFOUND ||
1384		       result == DNS_R_PARTIALMATCH);
1385
1386		/* Treat a partial match as no match */
1387		if (result == DNS_R_PARTIALMATCH) {
1388			dns_zone_detach(zp);
1389			result = ISC_R_NOTFOUND;
1390			POST(result);
1391		}
1392
1393		if (zone2 != NULL) {
1394			dns_zone_detach(&zone1);
1395			dns_zone_detach(&zone2);
1396			return (ISC_R_NOTFOUND);
1397		}
1398	}
1399
1400	if (zone1 != NULL) {
1401		dns_zone_attach(zone1, zonep);
1402		dns_zone_detach(&zone1);
1403		return (ISC_R_SUCCESS);
1404	}
1405
1406	return (ISC_R_NOTFOUND);
1407}
1408
1409isc_result_t
1410dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1411
1412	REQUIRE(DNS_VIEW_VALID(view));
1413
1414	return (dns_zt_load(view->zonetable, stop));
1415}
1416
1417isc_result_t
1418dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1419
1420	REQUIRE(DNS_VIEW_VALID(view));
1421
1422	return (dns_zt_loadnew(view->zonetable, stop));
1423}
1424#endif /* BIND9 */
1425
1426isc_result_t
1427dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1428{
1429	isc_result_t result;
1430	REQUIRE(keyp != NULL && *keyp == NULL);
1431
1432	result = dns_tsigkey_find(keyp, keyname, NULL,
1433				  view->statickeys);
1434	if (result == ISC_R_NOTFOUND)
1435		result = dns_tsigkey_find(keyp, keyname, NULL,
1436					  view->dynamickeys);
1437	return (result);
1438}
1439
1440isc_result_t
1441dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1442		     dns_tsigkey_t **keyp)
1443{
1444	isc_result_t result;
1445	dns_name_t *keyname = NULL;
1446	dns_peer_t *peer = NULL;
1447
1448	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1449	if (result != ISC_R_SUCCESS)
1450		return (result);
1451
1452	result = dns_peer_getkey(peer, &keyname);
1453	if (result != ISC_R_SUCCESS)
1454		return (result);
1455
1456	result = dns_view_gettsig(view, keyname, keyp);
1457	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1458}
1459
1460isc_result_t
1461dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1462	REQUIRE(DNS_VIEW_VALID(view));
1463	REQUIRE(source != NULL);
1464
1465	return (dns_tsig_verify(source, msg, view->statickeys,
1466				view->dynamickeys));
1467}
1468
1469#ifdef BIND9
1470isc_result_t
1471dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1472	isc_result_t result;
1473
1474	REQUIRE(DNS_VIEW_VALID(view));
1475
1476	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1477	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1478					 &dns_master_style_cache, fp);
1479	if (result != ISC_R_SUCCESS)
1480		return (result);
1481	dns_adb_dump(view->adb, fp);
1482	dns_resolver_printbadcache(view->resolver, fp);
1483	return (ISC_R_SUCCESS);
1484}
1485#endif
1486
1487isc_result_t
1488dns_view_flushcache(dns_view_t *view) {
1489	return (dns_view_flushcache2(view, ISC_FALSE));
1490}
1491
1492isc_result_t
1493dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1494	isc_result_t result;
1495
1496	REQUIRE(DNS_VIEW_VALID(view));
1497
1498	if (view->cachedb == NULL)
1499		return (ISC_R_SUCCESS);
1500	if (!fixuponly) {
1501		result = dns_cache_flush(view->cache);
1502		if (result != ISC_R_SUCCESS)
1503			return (result);
1504	}
1505#ifdef BIND9
1506	if (view->acache != NULL)
1507		dns_acache_putdb(view->acache, view->cachedb);
1508#endif
1509	dns_db_detach(&view->cachedb);
1510	dns_cache_attachdb(view->cache, &view->cachedb);
1511#ifdef BIND9
1512	if (view->acache != NULL)
1513		dns_acache_setdb(view->acache, view->cachedb);
1514	if (view->resolver != NULL)
1515		dns_resolver_flushbadcache(view->resolver, NULL);
1516#endif
1517
1518	dns_adb_flush(view->adb);
1519	return (ISC_R_SUCCESS);
1520}
1521
1522isc_result_t
1523dns_view_flushname(dns_view_t *view, dns_name_t *name) {
1524
1525	REQUIRE(DNS_VIEW_VALID(view));
1526
1527	if (view->adb != NULL)
1528		dns_adb_flushname(view->adb, name);
1529	if (view->cache == NULL)
1530		return (ISC_R_SUCCESS);
1531	if (view->resolver != NULL)
1532		dns_resolver_flushbadcache(view->resolver, name);
1533	return (dns_cache_flushname(view->cache, name));
1534}
1535
1536isc_result_t
1537dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1538	isc_result_t result;
1539	dns_name_t *new;
1540	isc_uint32_t hash;
1541
1542	REQUIRE(DNS_VIEW_VALID(view));
1543
1544	if (view->delonly == NULL) {
1545		view->delonly = isc_mem_get(view->mctx,
1546					    sizeof(dns_namelist_t) *
1547					    DNS_VIEW_DELONLYHASH);
1548		if (view->delonly == NULL)
1549			return (ISC_R_NOMEMORY);
1550		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1551			ISC_LIST_INIT(view->delonly[hash]);
1552	}
1553	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1554	new = ISC_LIST_HEAD(view->delonly[hash]);
1555	while (new != NULL && !dns_name_equal(new, name))
1556		new = ISC_LIST_NEXT(new, link);
1557	if (new != NULL)
1558		return (ISC_R_SUCCESS);
1559	new = isc_mem_get(view->mctx, sizeof(*new));
1560	if (new == NULL)
1561		return (ISC_R_NOMEMORY);
1562	dns_name_init(new, NULL);
1563	result = dns_name_dup(name, view->mctx, new);
1564	if (result == ISC_R_SUCCESS)
1565		ISC_LIST_APPEND(view->delonly[hash], new, link);
1566	else
1567		isc_mem_put(view->mctx, new, sizeof(*new));
1568	return (result);
1569}
1570
1571isc_result_t
1572dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1573	isc_result_t result;
1574	dns_name_t *new;
1575	isc_uint32_t hash;
1576
1577	REQUIRE(DNS_VIEW_VALID(view));
1578
1579	if (view->rootexclude == NULL) {
1580		view->rootexclude = isc_mem_get(view->mctx,
1581					    sizeof(dns_namelist_t) *
1582					    DNS_VIEW_DELONLYHASH);
1583		if (view->rootexclude == NULL)
1584			return (ISC_R_NOMEMORY);
1585		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1586			ISC_LIST_INIT(view->rootexclude[hash]);
1587	}
1588	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1589	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1590	while (new != NULL && !dns_name_equal(new, name))
1591		new = ISC_LIST_NEXT(new, link);
1592	if (new != NULL)
1593		return (ISC_R_SUCCESS);
1594	new = isc_mem_get(view->mctx, sizeof(*new));
1595	if (new == NULL)
1596		return (ISC_R_NOMEMORY);
1597	dns_name_init(new, NULL);
1598	result = dns_name_dup(name, view->mctx, new);
1599	if (result == ISC_R_SUCCESS)
1600		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1601	else
1602		isc_mem_put(view->mctx, new, sizeof(*new));
1603	return (result);
1604}
1605
1606isc_boolean_t
1607dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1608	dns_name_t *new;
1609	isc_uint32_t hash;
1610
1611	REQUIRE(DNS_VIEW_VALID(view));
1612
1613	if (!view->rootdelonly && view->delonly == NULL)
1614		return (ISC_FALSE);
1615
1616	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1617	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1618		if (view->rootexclude == NULL)
1619			return (ISC_TRUE);
1620		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1621		while (new != NULL && !dns_name_equal(new, name))
1622			new = ISC_LIST_NEXT(new, link);
1623		if (new == NULL)
1624			return (ISC_TRUE);
1625	}
1626
1627	if (view->delonly == NULL)
1628		return (ISC_FALSE);
1629
1630	new = ISC_LIST_HEAD(view->delonly[hash]);
1631	while (new != NULL && !dns_name_equal(new, name))
1632		new = ISC_LIST_NEXT(new, link);
1633	if (new == NULL)
1634		return (ISC_FALSE);
1635	return (ISC_TRUE);
1636}
1637
1638void
1639dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1640	REQUIRE(DNS_VIEW_VALID(view));
1641	view->rootdelonly = value;
1642}
1643
1644isc_boolean_t
1645dns_view_getrootdelonly(dns_view_t *view) {
1646	REQUIRE(DNS_VIEW_VALID(view));
1647	return (view->rootdelonly);
1648}
1649
1650#ifdef BIND9
1651isc_result_t
1652dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1653	REQUIRE(DNS_VIEW_VALID(view));
1654	return (dns_zt_freezezones(view->zonetable, value));
1655}
1656#endif
1657
1658void
1659dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1660	REQUIRE(DNS_VIEW_VALID(view));
1661	REQUIRE(!view->frozen);
1662	REQUIRE(view->resstats == NULL);
1663
1664	isc_stats_attach(stats, &view->resstats);
1665}
1666
1667void
1668dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1669	REQUIRE(DNS_VIEW_VALID(view));
1670	REQUIRE(statsp != NULL && *statsp == NULL);
1671
1672	if (view->resstats != NULL)
1673		isc_stats_attach(view->resstats, statsp);
1674}
1675
1676void
1677dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1678	REQUIRE(DNS_VIEW_VALID(view));
1679	REQUIRE(!view->frozen);
1680	REQUIRE(view->resquerystats == NULL);
1681
1682	dns_stats_attach(stats, &view->resquerystats);
1683}
1684
1685void
1686dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1687	REQUIRE(DNS_VIEW_VALID(view));
1688	REQUIRE(statsp != NULL && *statsp == NULL);
1689
1690	if (view->resquerystats != NULL)
1691		dns_stats_attach(view->resquerystats, statsp);
1692}
1693
1694isc_result_t
1695dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1696	REQUIRE(DNS_VIEW_VALID(view));
1697	if (view->secroots_priv != NULL)
1698		dns_keytable_detach(&view->secroots_priv);
1699	return (dns_keytable_create(mctx, &view->secroots_priv));
1700}
1701
1702isc_result_t
1703dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1704	REQUIRE(DNS_VIEW_VALID(view));
1705	REQUIRE(ktp != NULL && *ktp == NULL);
1706	if (view->secroots_priv == NULL)
1707		return (ISC_R_NOTFOUND);
1708	dns_keytable_attach(view->secroots_priv, ktp);
1709	return (ISC_R_SUCCESS);
1710}
1711
1712isc_result_t
1713dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1714			 isc_boolean_t *secure_domain) {
1715	REQUIRE(DNS_VIEW_VALID(view));
1716	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1717					    secure_domain));
1718}
1719
1720void
1721dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1722		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1723{
1724	isc_result_t result;
1725	unsigned char data[4096];
1726	dns_rdata_t rdata = DNS_RDATA_INIT;
1727	isc_buffer_t buffer;
1728	dst_key_t *key = NULL;
1729	dns_keytable_t *sr = NULL;
1730
1731	/*
1732	 * Clear the revoke bit, if set, so that the key will match what's
1733	 * in secroots now.
1734	 */
1735	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1736
1737	/* Convert dnskey to DST key. */
1738	isc_buffer_init(&buffer, data, sizeof(data));
1739	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1740			     dns_rdatatype_dnskey, dnskey, &buffer);
1741	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1742	if (result != ISC_R_SUCCESS)
1743		return;
1744	result = dns_view_getsecroots(view, &sr);
1745	if (result == ISC_R_SUCCESS) {
1746		dns_keytable_deletekeynode(sr, key);
1747		dns_keytable_detach(&sr);
1748	}
1749	dst_key_free(&key);
1750}
1751
1752#define NZF ".nzf"
1753
1754void
1755dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1756		     void (*cfg_destroy)(void **))
1757{
1758	REQUIRE(DNS_VIEW_VALID(view));
1759	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1760
1761#ifdef BIND9
1762	if (view->new_zone_file != NULL) {
1763		isc_mem_free(view->mctx, view->new_zone_file);
1764		view->new_zone_file = NULL;
1765	}
1766
1767	if (view->new_zone_config != NULL) {
1768		view->cfg_destroy(&view->new_zone_config);
1769		view->cfg_destroy = NULL;
1770	}
1771
1772	if (allow) {
1773		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1774		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1775		/* Truncate the hash at 16 chars; full length is overkill */
1776		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1777		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1778		view->new_zone_config = cfgctx;
1779		view->cfg_destroy = cfg_destroy;
1780	}
1781#else
1782	UNUSED(allow);
1783	UNUSED(cfgctx);
1784	UNUSED(cfg_destroy);
1785#endif
1786}
1787