view.c revision 245163
1178525Sjb/*
2178525Sjb * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3178525Sjb * Copyright (C) 1999-2003  Internet Software Consortium.
4178525Sjb *
5178525Sjb * Permission to use, copy, modify, and/or distribute this software for any
6178525Sjb * purpose with or without fee is hereby granted, provided that the above
7178525Sjb * copyright notice and this permission notice appear in all copies.
8178525Sjb *
9178525Sjb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10178525Sjb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11178525Sjb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12178525Sjb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13178525Sjb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14178525Sjb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15178525Sjb * PERFORMANCE OF THIS SOFTWARE.
16178525Sjb */
17178525Sjb
18178525Sjb/* $Id$ */
19178525Sjb
20178525Sjb/*! \file */
21178525Sjb
22178525Sjb#include <config.h>
23178525Sjb
24178525Sjb#include <isc/file.h>
25178525Sjb#include <isc/hash.h>
26178525Sjb#include <isc/print.h>
27178525Sjb#include <isc/sha2.h>
28178525Sjb#include <isc/stats.h>
29178525Sjb#include <isc/string.h>		/* Required for HP/UX (and others?) */
30178525Sjb#include <isc/task.h>
31178525Sjb#include <isc/util.h>
32178525Sjb
33178525Sjb#include <dns/acache.h>
34178525Sjb#include <dns/acl.h>
35178525Sjb#include <dns/adb.h>
36178525Sjb#include <dns/cache.h>
37178525Sjb#include <dns/db.h>
38178525Sjb#include <dns/dlz.h>
39178525Sjb#ifdef BIND9
40178525Sjb#include <dns/dns64.h>
41178525Sjb#endif
42178525Sjb#include <dns/dnssec.h>
43178525Sjb#include <dns/events.h>
44178525Sjb#include <dns/forward.h>
45178525Sjb#include <dns/keytable.h>
46178525Sjb#include <dns/keyvalues.h>
47178525Sjb#include <dns/master.h>
48178525Sjb#include <dns/masterdump.h>
49178525Sjb#include <dns/order.h>
50178525Sjb#include <dns/peer.h>
51178525Sjb#include <dns/rbt.h>
52178525Sjb#include <dns/rdataset.h>
53178525Sjb#include <dns/request.h>
54178525Sjb#include <dns/resolver.h>
55#include <dns/result.h>
56#include <dns/rpz.h>
57#include <dns/stats.h>
58#include <dns/tsig.h>
59#include <dns/zone.h>
60#include <dns/zt.h>
61
62#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
63#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
64#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
65
66#define DNS_VIEW_DELONLYHASH 111
67
68static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
69static void adb_shutdown(isc_task_t *task, isc_event_t *event);
70static void req_shutdown(isc_task_t *task, isc_event_t *event);
71
72isc_result_t
73dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
74		const char *name, dns_view_t **viewp)
75{
76	dns_view_t *view;
77	isc_result_t result;
78
79	/*
80	 * Create a view.
81	 */
82
83	REQUIRE(name != NULL);
84	REQUIRE(viewp != NULL && *viewp == NULL);
85
86	view = isc_mem_get(mctx, sizeof(*view));
87	if (view == NULL)
88		return (ISC_R_NOMEMORY);
89	view->name = isc_mem_strdup(mctx, name);
90	if (view->name == NULL) {
91		result = ISC_R_NOMEMORY;
92		goto cleanup_view;
93	}
94	result = isc_mutex_init(&view->lock);
95	if (result != ISC_R_SUCCESS)
96		goto cleanup_name;
97
98#ifdef BIND9
99	view->zonetable = NULL;
100	result = dns_zt_create(mctx, rdclass, &view->zonetable);
101	if (result != ISC_R_SUCCESS) {
102		UNEXPECTED_ERROR(__FILE__, __LINE__,
103				 "dns_zt_create() failed: %s",
104				 isc_result_totext(result));
105		result = ISC_R_UNEXPECTED;
106		goto cleanup_mutex;
107	}
108#endif
109	view->secroots_priv = NULL;
110	view->fwdtable = NULL;
111	result = dns_fwdtable_create(mctx, &view->fwdtable);
112	if (result != ISC_R_SUCCESS) {
113		UNEXPECTED_ERROR(__FILE__, __LINE__,
114				 "dns_fwdtable_create() failed: %s",
115				 isc_result_totext(result));
116		result = ISC_R_UNEXPECTED;
117		goto cleanup_zt;
118	}
119
120	view->acache = NULL;
121	view->cache = NULL;
122	view->cachedb = NULL;
123	view->dlzdatabase = NULL;
124	view->hints = NULL;
125	view->resolver = NULL;
126	view->adb = NULL;
127	view->requestmgr = NULL;
128	view->mctx = mctx;
129	view->rdclass = rdclass;
130	view->frozen = ISC_FALSE;
131	view->task = NULL;
132	result = isc_refcount_init(&view->references, 1);
133	if (result != ISC_R_SUCCESS)
134		goto cleanup_fwdtable;
135	view->weakrefs = 0;
136	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
137			    DNS_VIEWATTR_REQSHUTDOWN);
138	view->statickeys = NULL;
139	view->dynamickeys = NULL;
140	view->matchclients = NULL;
141	view->matchdestinations = NULL;
142	view->matchrecursiveonly = ISC_FALSE;
143	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
144	if (result != ISC_R_SUCCESS)
145		goto cleanup_references;
146	view->peers = NULL;
147	view->order = NULL;
148	view->delonly = NULL;
149	view->rootdelonly = ISC_FALSE;
150	view->rootexclude = NULL;
151	view->resstats = NULL;
152	view->resquerystats = NULL;
153	view->cacheshared = ISC_FALSE;
154	ISC_LIST_INIT(view->dns64);
155	view->dns64cnt = 0;
156
157	/*
158	 * Initialize configuration data with default values.
159	 */
160	view->recursion = ISC_TRUE;
161	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
162	view->additionalfromcache = ISC_TRUE;
163	view->additionalfromauth = ISC_TRUE;
164	view->enablednssec = ISC_TRUE;
165	view->enablevalidation = ISC_TRUE;
166	view->acceptexpired = ISC_FALSE;
167	view->minimalresponses = ISC_FALSE;
168	view->transfer_format = dns_one_answer;
169	view->cacheacl = NULL;
170	view->cacheonacl = NULL;
171	view->queryacl = NULL;
172	view->queryonacl = NULL;
173	view->recursionacl = NULL;
174	view->recursiononacl = NULL;
175	view->sortlist = NULL;
176	view->transferacl = NULL;
177	view->notifyacl = NULL;
178	view->updateacl = NULL;
179	view->upfwdacl = NULL;
180	view->denyansweracl = NULL;
181	view->answeracl_exclude = NULL;
182	view->denyanswernames = NULL;
183	view->answernames_exclude = NULL;
184	view->requestixfr = ISC_TRUE;
185	view->provideixfr = ISC_TRUE;
186	view->maxcachettl = 7 * 24 * 3600;
187	view->maxncachettl = 3 * 3600;
188	view->dstport = 53;
189	view->preferred_glue = 0;
190	view->flush = ISC_FALSE;
191	view->dlv = NULL;
192	view->maxudp = 0;
193	view->v4_aaaa = dns_v4_aaaa_ok;
194	view->v4_aaaa_acl = NULL;
195	ISC_LIST_INIT(view->rpz_zones);
196	view->rpz_recursive_only = ISC_TRUE;
197	view->rpz_break_dnssec = ISC_FALSE;
198	dns_fixedname_init(&view->dlv_fixed);
199	view->managed_keys = NULL;
200#ifdef BIND9
201	view->new_zone_file = NULL;
202	view->new_zone_config = NULL;
203	view->cfg_destroy = NULL;
204
205	result = dns_order_create(view->mctx, &view->order);
206	if (result != ISC_R_SUCCESS)
207		goto cleanup_dynkeys;
208#endif
209
210	result = dns_peerlist_new(view->mctx, &view->peers);
211	if (result != ISC_R_SUCCESS)
212		goto cleanup_order;
213
214	result = dns_aclenv_init(view->mctx, &view->aclenv);
215	if (result != ISC_R_SUCCESS)
216		goto cleanup_peerlist;
217
218	ISC_LINK_INIT(view, link);
219	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
220		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
221		       view, NULL, NULL, NULL);
222	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
223		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
224		       view, NULL, NULL, NULL);
225	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
226		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
227		       view, NULL, NULL, NULL);
228	view->magic = DNS_VIEW_MAGIC;
229
230	*viewp = view;
231
232	return (ISC_R_SUCCESS);
233
234 cleanup_peerlist:
235	dns_peerlist_detach(&view->peers);
236
237 cleanup_order:
238#ifdef BIND9
239	dns_order_detach(&view->order);
240
241 cleanup_dynkeys:
242#endif
243	dns_tsigkeyring_detach(&view->dynamickeys);
244
245 cleanup_references:
246	isc_refcount_destroy(&view->references);
247
248 cleanup_fwdtable:
249	dns_fwdtable_destroy(&view->fwdtable);
250
251 cleanup_zt:
252#ifdef BIND9
253	dns_zt_detach(&view->zonetable);
254
255 cleanup_mutex:
256#endif
257	DESTROYLOCK(&view->lock);
258
259 cleanup_name:
260	isc_mem_free(mctx, view->name);
261
262 cleanup_view:
263	isc_mem_put(mctx, view, sizeof(*view));
264
265	return (result);
266}
267
268static inline void
269destroy(dns_view_t *view) {
270#ifdef BIND9
271	dns_dns64_t *dns64;
272#endif
273
274	REQUIRE(!ISC_LINK_LINKED(view, link));
275	REQUIRE(isc_refcount_current(&view->references) == 0);
276	REQUIRE(view->weakrefs == 0);
277	REQUIRE(RESSHUTDOWN(view));
278	REQUIRE(ADBSHUTDOWN(view));
279	REQUIRE(REQSHUTDOWN(view));
280
281#ifdef BIND9
282	if (view->order != NULL)
283		dns_order_detach(&view->order);
284#endif
285	if (view->peers != NULL)
286		dns_peerlist_detach(&view->peers);
287
288	if (view->dynamickeys != NULL) {
289		isc_result_t result;
290		char template[20];
291		char keyfile[20];
292		FILE *fp = NULL;
293		int n;
294
295		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
296			     view->name);
297		if (n > 0 && (size_t)n < sizeof(keyfile)) {
298			result = isc_file_mktemplate(keyfile, template,
299						     sizeof(template));
300			if (result == ISC_R_SUCCESS)
301				(void)isc_file_openuniqueprivate(template, &fp);
302		}
303		if (fp == NULL)
304			dns_tsigkeyring_detach(&view->dynamickeys);
305		else {
306			result = dns_tsigkeyring_dumpanddetach(
307							&view->dynamickeys, fp);
308			if (result == ISC_R_SUCCESS) {
309				if (fclose(fp) == 0)
310					result = isc_file_rename(template,
311								 keyfile);
312				if (result != ISC_R_SUCCESS)
313					(void)remove(template);
314			} else {
315				(void)fclose(fp);
316				(void)remove(template);
317			}
318		}
319	}
320	if (view->statickeys != NULL)
321		dns_tsigkeyring_detach(&view->statickeys);
322	if (view->adb != NULL)
323		dns_adb_detach(&view->adb);
324	if (view->resolver != NULL)
325		dns_resolver_detach(&view->resolver);
326#ifdef BIND9
327	if (view->acache != NULL) {
328		if (view->cachedb != NULL)
329			dns_acache_putdb(view->acache, view->cachedb);
330		dns_acache_detach(&view->acache);
331	}
332	dns_rpz_view_destroy(view);
333#else
334	INSIST(view->acache == NULL);
335	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
336#endif
337	if (view->requestmgr != NULL)
338		dns_requestmgr_detach(&view->requestmgr);
339	if (view->task != NULL)
340		isc_task_detach(&view->task);
341	if (view->hints != NULL)
342		dns_db_detach(&view->hints);
343	if (view->dlzdatabase != NULL)
344		dns_dlzdestroy(&view->dlzdatabase);
345	if (view->cachedb != NULL)
346		dns_db_detach(&view->cachedb);
347	if (view->cache != NULL)
348		dns_cache_detach(&view->cache);
349	if (view->matchclients != NULL)
350		dns_acl_detach(&view->matchclients);
351	if (view->matchdestinations != NULL)
352		dns_acl_detach(&view->matchdestinations);
353	if (view->cacheacl != NULL)
354		dns_acl_detach(&view->cacheacl);
355	if (view->cacheonacl != NULL)
356		dns_acl_detach(&view->cacheonacl);
357	if (view->queryacl != NULL)
358		dns_acl_detach(&view->queryacl);
359	if (view->queryonacl != NULL)
360		dns_acl_detach(&view->queryonacl);
361	if (view->recursionacl != NULL)
362		dns_acl_detach(&view->recursionacl);
363	if (view->recursiononacl != NULL)
364		dns_acl_detach(&view->recursiononacl);
365	if (view->sortlist != NULL)
366		dns_acl_detach(&view->sortlist);
367	if (view->transferacl != NULL)
368		dns_acl_detach(&view->transferacl);
369	if (view->notifyacl != NULL)
370		dns_acl_detach(&view->notifyacl);
371	if (view->updateacl != NULL)
372		dns_acl_detach(&view->updateacl);
373	if (view->upfwdacl != NULL)
374		dns_acl_detach(&view->upfwdacl);
375	if (view->denyansweracl != NULL)
376		dns_acl_detach(&view->denyansweracl);
377	if (view->v4_aaaa_acl != NULL)
378		dns_acl_detach(&view->v4_aaaa_acl);
379	if (view->answeracl_exclude != NULL)
380		dns_rbt_destroy(&view->answeracl_exclude);
381	if (view->denyanswernames != NULL)
382		dns_rbt_destroy(&view->denyanswernames);
383	if (view->answernames_exclude != NULL)
384		dns_rbt_destroy(&view->answernames_exclude);
385	if (view->delonly != NULL) {
386		dns_name_t *name;
387		int i;
388
389		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
390			name = ISC_LIST_HEAD(view->delonly[i]);
391			while (name != NULL) {
392				ISC_LIST_UNLINK(view->delonly[i], name, link);
393				dns_name_free(name, view->mctx);
394				isc_mem_put(view->mctx, name, sizeof(*name));
395				name = ISC_LIST_HEAD(view->delonly[i]);
396			}
397		}
398		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
399			    DNS_VIEW_DELONLYHASH);
400		view->delonly = NULL;
401	}
402	if (view->rootexclude != NULL) {
403		dns_name_t *name;
404		int i;
405
406		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
407			name = ISC_LIST_HEAD(view->rootexclude[i]);
408			while (name != NULL) {
409				ISC_LIST_UNLINK(view->rootexclude[i],
410						name, link);
411				dns_name_free(name, view->mctx);
412				isc_mem_put(view->mctx, name, sizeof(*name));
413				name = ISC_LIST_HEAD(view->rootexclude[i]);
414			}
415		}
416		isc_mem_put(view->mctx, view->rootexclude,
417			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
418		view->rootexclude = NULL;
419	}
420	if (view->resstats != NULL)
421		isc_stats_detach(&view->resstats);
422	if (view->resquerystats != NULL)
423		dns_stats_detach(&view->resquerystats);
424	if (view->secroots_priv != NULL)
425		dns_keytable_detach(&view->secroots_priv);
426#ifdef BIND9
427	for (dns64 = ISC_LIST_HEAD(view->dns64);
428	     dns64 != NULL;
429	     dns64 = ISC_LIST_HEAD(view->dns64)) {
430		dns_dns64_unlink(&view->dns64, dns64);
431		dns_dns64_destroy(&dns64);
432	}
433	if (view->managed_keys != NULL)
434		dns_zone_detach(&view->managed_keys);
435	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
436#endif
437	dns_fwdtable_destroy(&view->fwdtable);
438	dns_aclenv_destroy(&view->aclenv);
439	DESTROYLOCK(&view->lock);
440	isc_refcount_destroy(&view->references);
441	isc_mem_free(view->mctx, view->name);
442	isc_mem_put(view->mctx, view, sizeof(*view));
443}
444
445/*
446 * Return true iff 'view' may be freed.
447 * The caller must be holding the view lock.
448 */
449static isc_boolean_t
450all_done(dns_view_t *view) {
451
452	if (isc_refcount_current(&view->references) == 0 &&
453	    view->weakrefs == 0 &&
454	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
455		return (ISC_TRUE);
456
457	return (ISC_FALSE);
458}
459
460void
461dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
462
463	REQUIRE(DNS_VIEW_VALID(source));
464	REQUIRE(targetp != NULL && *targetp == NULL);
465
466	isc_refcount_increment(&source->references, NULL);
467
468	*targetp = source;
469}
470
471static void
472view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
473	dns_view_t *view;
474	unsigned int refs;
475	isc_boolean_t done = ISC_FALSE;
476
477	REQUIRE(viewp != NULL);
478	view = *viewp;
479	REQUIRE(DNS_VIEW_VALID(view));
480
481	if (flush)
482		view->flush = ISC_TRUE;
483	isc_refcount_decrement(&view->references, &refs);
484	if (refs == 0) {
485		LOCK(&view->lock);
486		if (!RESSHUTDOWN(view))
487			dns_resolver_shutdown(view->resolver);
488		if (!ADBSHUTDOWN(view))
489			dns_adb_shutdown(view->adb);
490		if (!REQSHUTDOWN(view))
491			dns_requestmgr_shutdown(view->requestmgr);
492#ifdef BIND9
493		if (view->acache != NULL)
494			dns_acache_shutdown(view->acache);
495		if (view->flush)
496			dns_zt_flushanddetach(&view->zonetable);
497		else
498			dns_zt_detach(&view->zonetable);
499		if (view->managed_keys != NULL) {
500			if (view->flush)
501				dns_zone_flush(view->managed_keys);
502			dns_zone_detach(&view->managed_keys);
503		}
504#endif
505		done = all_done(view);
506		UNLOCK(&view->lock);
507	}
508
509	*viewp = NULL;
510
511	if (done)
512		destroy(view);
513}
514
515void
516dns_view_flushanddetach(dns_view_t **viewp) {
517	view_flushanddetach(viewp, ISC_TRUE);
518}
519
520void
521dns_view_detach(dns_view_t **viewp) {
522	view_flushanddetach(viewp, ISC_FALSE);
523}
524
525#ifdef BIND9
526static isc_result_t
527dialup(dns_zone_t *zone, void *dummy) {
528	UNUSED(dummy);
529	dns_zone_dialup(zone);
530	return (ISC_R_SUCCESS);
531}
532
533void
534dns_view_dialup(dns_view_t *view) {
535	REQUIRE(DNS_VIEW_VALID(view));
536	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
537}
538#endif
539
540void
541dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
542
543	REQUIRE(DNS_VIEW_VALID(source));
544	REQUIRE(targetp != NULL && *targetp == NULL);
545
546	LOCK(&source->lock);
547	source->weakrefs++;
548	UNLOCK(&source->lock);
549
550	*targetp = source;
551}
552
553void
554dns_view_weakdetach(dns_view_t **viewp) {
555	dns_view_t *view;
556	isc_boolean_t done = ISC_FALSE;
557
558	REQUIRE(viewp != NULL);
559	view = *viewp;
560	REQUIRE(DNS_VIEW_VALID(view));
561
562	LOCK(&view->lock);
563
564	INSIST(view->weakrefs > 0);
565	view->weakrefs--;
566	done = all_done(view);
567
568	UNLOCK(&view->lock);
569
570	*viewp = NULL;
571
572	if (done)
573		destroy(view);
574}
575
576static void
577resolver_shutdown(isc_task_t *task, isc_event_t *event) {
578	dns_view_t *view = event->ev_arg;
579	isc_boolean_t done;
580
581	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
582	REQUIRE(DNS_VIEW_VALID(view));
583	REQUIRE(view->task == task);
584
585	UNUSED(task);
586
587	LOCK(&view->lock);
588
589	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
590	done = all_done(view);
591
592	UNLOCK(&view->lock);
593
594	isc_event_free(&event);
595
596	if (done)
597		destroy(view);
598}
599
600static void
601adb_shutdown(isc_task_t *task, isc_event_t *event) {
602	dns_view_t *view = event->ev_arg;
603	isc_boolean_t done;
604
605	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
606	REQUIRE(DNS_VIEW_VALID(view));
607	REQUIRE(view->task == task);
608
609	UNUSED(task);
610
611	LOCK(&view->lock);
612
613	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
614	done = all_done(view);
615
616	UNLOCK(&view->lock);
617
618	isc_event_free(&event);
619
620	if (done)
621		destroy(view);
622}
623
624static void
625req_shutdown(isc_task_t *task, isc_event_t *event) {
626	dns_view_t *view = event->ev_arg;
627	isc_boolean_t done;
628
629	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
630	REQUIRE(DNS_VIEW_VALID(view));
631	REQUIRE(view->task == task);
632
633	UNUSED(task);
634
635	LOCK(&view->lock);
636
637	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
638	done = all_done(view);
639
640	UNLOCK(&view->lock);
641
642	isc_event_free(&event);
643
644	if (done)
645		destroy(view);
646}
647
648isc_result_t
649dns_view_createresolver(dns_view_t *view,
650			isc_taskmgr_t *taskmgr, unsigned int ntasks,
651			isc_socketmgr_t *socketmgr,
652			isc_timermgr_t *timermgr,
653			unsigned int options,
654			dns_dispatchmgr_t *dispatchmgr,
655			dns_dispatch_t *dispatchv4,
656			dns_dispatch_t *dispatchv6)
657{
658	isc_result_t result;
659	isc_event_t *event;
660	isc_mem_t *mctx = NULL;
661
662	REQUIRE(DNS_VIEW_VALID(view));
663	REQUIRE(!view->frozen);
664	REQUIRE(view->resolver == NULL);
665
666	result = isc_task_create(taskmgr, 0, &view->task);
667	if (result != ISC_R_SUCCESS)
668		return (result);
669	isc_task_setname(view->task, "view", view);
670
671	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
672				     timermgr, options, dispatchmgr,
673				     dispatchv4, dispatchv6,
674				     &view->resolver);
675	if (result != ISC_R_SUCCESS) {
676		isc_task_detach(&view->task);
677		return (result);
678	}
679	event = &view->resevent;
680	dns_resolver_whenshutdown(view->resolver, view->task, &event);
681	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
682
683	result = isc_mem_create(0, 0, &mctx);
684	if (result != ISC_R_SUCCESS) {
685		dns_resolver_shutdown(view->resolver);
686		return (result);
687	}
688
689	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
690	isc_mem_setname(mctx, "ADB", NULL);
691	isc_mem_detach(&mctx);
692	if (result != ISC_R_SUCCESS) {
693		dns_resolver_shutdown(view->resolver);
694		return (result);
695	}
696	event = &view->adbevent;
697	dns_adb_whenshutdown(view->adb, view->task, &event);
698	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
699
700	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
701				      dns_resolver_taskmgr(view->resolver),
702				      dns_resolver_dispatchmgr(view->resolver),
703				      dns_resolver_dispatchv4(view->resolver),
704				      dns_resolver_dispatchv6(view->resolver),
705				      &view->requestmgr);
706	if (result != ISC_R_SUCCESS) {
707		dns_adb_shutdown(view->adb);
708		dns_resolver_shutdown(view->resolver);
709		return (result);
710	}
711	event = &view->reqevent;
712	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
713	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
714
715	return (ISC_R_SUCCESS);
716}
717
718void
719dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
720	dns_view_setcache2(view, cache, ISC_FALSE);
721}
722
723void
724dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
725	REQUIRE(DNS_VIEW_VALID(view));
726	REQUIRE(!view->frozen);
727
728	view->cacheshared = shared;
729	if (view->cache != NULL) {
730#ifdef BIND9
731		if (view->acache != NULL)
732			dns_acache_putdb(view->acache, view->cachedb);
733#endif
734		dns_db_detach(&view->cachedb);
735		dns_cache_detach(&view->cache);
736	}
737	dns_cache_attach(cache, &view->cache);
738	dns_cache_attachdb(cache, &view->cachedb);
739	INSIST(DNS_DB_VALID(view->cachedb));
740
741#ifdef BIND9
742	if (view->acache != NULL)
743		dns_acache_setdb(view->acache, view->cachedb);
744#endif
745}
746
747isc_boolean_t
748dns_view_iscacheshared(dns_view_t *view) {
749	REQUIRE(DNS_VIEW_VALID(view));
750
751	return (view->cacheshared);
752}
753
754void
755dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
756	REQUIRE(DNS_VIEW_VALID(view));
757	REQUIRE(!view->frozen);
758	REQUIRE(view->hints == NULL);
759	REQUIRE(dns_db_iszone(hints));
760
761	dns_db_attach(hints, &view->hints);
762}
763
764void
765dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
766	REQUIRE(DNS_VIEW_VALID(view));
767	REQUIRE(ring != NULL);
768	if (view->statickeys != NULL)
769		dns_tsigkeyring_detach(&view->statickeys);
770	dns_tsigkeyring_attach(ring, &view->statickeys);
771}
772
773void
774dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
775	REQUIRE(DNS_VIEW_VALID(view));
776	REQUIRE(ring != NULL);
777	if (view->dynamickeys != NULL)
778		dns_tsigkeyring_detach(&view->dynamickeys);
779	dns_tsigkeyring_attach(ring, &view->dynamickeys);
780}
781
782void
783dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
784	REQUIRE(DNS_VIEW_VALID(view));
785	REQUIRE(ringp != NULL && *ringp == NULL);
786	if (view->dynamickeys != NULL)
787		dns_tsigkeyring_attach(view->dynamickeys, ringp);
788}
789
790void
791dns_view_restorekeyring(dns_view_t *view) {
792	FILE *fp;
793	char keyfile[20];
794	int n;
795
796	REQUIRE(DNS_VIEW_VALID(view));
797
798	if (view->dynamickeys != NULL) {
799		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
800			     view->name);
801		if (n > 0 && (size_t)n < sizeof(keyfile)) {
802			fp = fopen(keyfile, "r");
803			if (fp != NULL) {
804				dns_keyring_restore(view->dynamickeys, fp);
805				(void)fclose(fp);
806			}
807		}
808	}
809}
810
811void
812dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
813	REQUIRE(DNS_VIEW_VALID(view));
814	view->dstport = dstport;
815}
816
817void
818dns_view_freeze(dns_view_t *view) {
819	REQUIRE(DNS_VIEW_VALID(view));
820	REQUIRE(!view->frozen);
821
822	if (view->resolver != NULL) {
823		INSIST(view->cachedb != NULL);
824		dns_resolver_freeze(view->resolver);
825	}
826	view->frozen = ISC_TRUE;
827}
828
829#ifdef BIND9
830void
831dns_view_thaw(dns_view_t *view) {
832	REQUIRE(DNS_VIEW_VALID(view));
833	REQUIRE(view->frozen);
834
835	view->frozen = ISC_FALSE;
836}
837
838isc_result_t
839dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
840	isc_result_t result;
841
842	REQUIRE(DNS_VIEW_VALID(view));
843	REQUIRE(!view->frozen);
844
845	result = dns_zt_mount(view->zonetable, zone);
846
847	return (result);
848}
849#endif
850
851#ifdef BIND9
852isc_result_t
853dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
854	isc_result_t result;
855
856	REQUIRE(DNS_VIEW_VALID(view));
857
858	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
859	if (result == DNS_R_PARTIALMATCH) {
860		dns_zone_detach(zonep);
861		result = ISC_R_NOTFOUND;
862	}
863
864	return (result);
865}
866#endif
867
868isc_result_t
869dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
870	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
871	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
872	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
873	return (dns_view_find2(view, name, type, now, options, use_hints,
874			       ISC_FALSE, dbp, nodep, foundname, rdataset,
875			       sigrdataset));
876}
877
878isc_result_t
879dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
880	       isc_stdtime_t now, unsigned int options,
881	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
882	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
883	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
884{
885	isc_result_t result;
886	dns_db_t *db, *zdb;
887	dns_dbnode_t *node, *znode;
888	isc_boolean_t is_cache, is_staticstub_zone;
889	dns_rdataset_t zrdataset, zsigrdataset;
890	dns_zone_t *zone;
891
892#ifndef BIND9
893	UNUSED(use_hints);
894	UNUSED(use_static_stub);
895#endif
896
897	/*
898	 * Find an rdataset whose owner name is 'name', and whose type is
899	 * 'type'.
900	 */
901
902	REQUIRE(DNS_VIEW_VALID(view));
903	REQUIRE(view->frozen);
904	REQUIRE(type != dns_rdatatype_rrsig);
905	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
906	REQUIRE(nodep == NULL || *nodep == NULL);
907
908	/*
909	 * Initialize.
910	 */
911	dns_rdataset_init(&zrdataset);
912	dns_rdataset_init(&zsigrdataset);
913	zdb = NULL;
914	znode = NULL;
915
916	/*
917	 * Find a database to answer the query.
918	 */
919	zone = NULL;
920	db = NULL;
921	node = NULL;
922	is_staticstub_zone = ISC_FALSE;
923#ifdef BIND9
924	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
925	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
926	    !use_static_stub) {
927		result = ISC_R_NOTFOUND;
928	}
929	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
930		result = dns_zone_getdb(zone, &db);
931		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
932			dns_db_attach(view->cachedb, &db);
933		else if (result != ISC_R_SUCCESS)
934			goto cleanup;
935		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
936		    dns_name_equal(name, dns_zone_getorigin(zone))) {
937			is_staticstub_zone = ISC_TRUE;
938		}
939	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
940		dns_db_attach(view->cachedb, &db);
941#else
942	result = ISC_R_NOTFOUND;
943	if (view->cachedb != NULL)
944		dns_db_attach(view->cachedb, &db);
945#endif /* BIND9 */
946	else
947		goto cleanup;
948
949	is_cache = dns_db_iscache(db);
950
951 db_find:
952	/*
953	 * Now look for an answer in the database.
954	 */
955	result = dns_db_find(db, name, NULL, type, options,
956			     now, &node, foundname, rdataset, sigrdataset);
957
958	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
959		if (dns_rdataset_isassociated(rdataset))
960			dns_rdataset_disassociate(rdataset);
961		if (sigrdataset != NULL &&
962		    dns_rdataset_isassociated(sigrdataset))
963			dns_rdataset_disassociate(sigrdataset);
964		if (node != NULL)
965			dns_db_detachnode(db, &node);
966		if (!is_cache) {
967			dns_db_detach(&db);
968			if (view->cachedb != NULL && !is_staticstub_zone) {
969				/*
970				 * Either the answer is in the cache, or we
971				 * don't know it.
972				 * Note that if the result comes from a
973				 * static-stub zone we stop the search here
974				 * (see the function description in view.h).
975				 */
976				is_cache = ISC_TRUE;
977				dns_db_attach(view->cachedb, &db);
978				goto db_find;
979			}
980		} else {
981			/*
982			 * We don't have the data in the cache.  If we've got
983			 * glue from the zone, use it.
984			 */
985			if (dns_rdataset_isassociated(&zrdataset)) {
986				dns_rdataset_clone(&zrdataset, rdataset);
987				if (sigrdataset != NULL &&
988				    dns_rdataset_isassociated(&zsigrdataset))
989					dns_rdataset_clone(&zsigrdataset,
990							   sigrdataset);
991				result = DNS_R_GLUE;
992				if (db != NULL)
993					dns_db_detach(&db);
994				dns_db_attach(zdb, &db);
995				dns_db_attachnode(db, znode, &node);
996				goto cleanup;
997			}
998		}
999		/*
1000		 * We don't know the answer.
1001		 */
1002		result = ISC_R_NOTFOUND;
1003	} else if (result == DNS_R_GLUE) {
1004		if (view->cachedb != NULL && !is_staticstub_zone) {
1005			/*
1006			 * We found an answer, but the cache may be better.
1007			 * Remember what we've got and go look in the cache.
1008			 */
1009			is_cache = ISC_TRUE;
1010			dns_rdataset_clone(rdataset, &zrdataset);
1011			dns_rdataset_disassociate(rdataset);
1012			if (sigrdataset != NULL &&
1013			    dns_rdataset_isassociated(sigrdataset)) {
1014				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1015				dns_rdataset_disassociate(sigrdataset);
1016			}
1017			dns_db_attach(db, &zdb);
1018			dns_db_attachnode(zdb, node, &znode);
1019			dns_db_detachnode(db, &node);
1020			dns_db_detach(&db);
1021			dns_db_attach(view->cachedb, &db);
1022			goto db_find;
1023		}
1024		/*
1025		 * Otherwise, the glue is the best answer.
1026		 */
1027		result = ISC_R_SUCCESS;
1028	}
1029
1030#ifdef BIND9
1031	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1032		if (dns_rdataset_isassociated(rdataset))
1033			dns_rdataset_disassociate(rdataset);
1034		if (sigrdataset != NULL &&
1035		    dns_rdataset_isassociated(sigrdataset))
1036			dns_rdataset_disassociate(sigrdataset);
1037		if (db != NULL) {
1038			if (node != NULL)
1039				dns_db_detachnode(db, &node);
1040			dns_db_detach(&db);
1041		}
1042		result = dns_db_find(view->hints, name, NULL, type, options,
1043				     now, &node, foundname,
1044				     rdataset, sigrdataset);
1045		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1046			/*
1047			 * We just used a hint.  Let the resolver know it
1048			 * should consider priming.
1049			 */
1050			dns_resolver_prime(view->resolver);
1051			dns_db_attach(view->hints, &db);
1052			result = DNS_R_HINT;
1053		} else if (result == DNS_R_NXRRSET) {
1054			dns_db_attach(view->hints, &db);
1055			result = DNS_R_HINTNXRRSET;
1056		} else if (result == DNS_R_NXDOMAIN)
1057			result = ISC_R_NOTFOUND;
1058
1059		/*
1060		 * Cleanup if non-standard hints are used.
1061		 */
1062		if (db == NULL && node != NULL)
1063			dns_db_detachnode(view->hints, &node);
1064	}
1065#endif /* BIND9 */
1066
1067 cleanup:
1068	if (dns_rdataset_isassociated(&zrdataset)) {
1069		dns_rdataset_disassociate(&zrdataset);
1070		if (dns_rdataset_isassociated(&zsigrdataset))
1071			dns_rdataset_disassociate(&zsigrdataset);
1072	}
1073
1074	if (zdb != NULL) {
1075		if (znode != NULL)
1076			dns_db_detachnode(zdb, &znode);
1077		dns_db_detach(&zdb);
1078	}
1079
1080	if (db != NULL) {
1081		if (node != NULL) {
1082			if (nodep != NULL)
1083				*nodep = node;
1084			else
1085				dns_db_detachnode(db, &node);
1086		}
1087		if (dbp != NULL)
1088			*dbp = db;
1089		else
1090			dns_db_detach(&db);
1091	} else
1092		INSIST(node == NULL);
1093
1094#ifdef BIND9
1095	if (zone != NULL)
1096		dns_zone_detach(&zone);
1097#endif
1098
1099	return (result);
1100}
1101
1102isc_result_t
1103dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1104		    isc_stdtime_t now, unsigned int options,
1105		    isc_boolean_t use_hints,
1106		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1107{
1108	isc_result_t result;
1109	dns_fixedname_t foundname;
1110
1111	dns_fixedname_init(&foundname);
1112	result = dns_view_find(view, name, type, now, options, use_hints,
1113			       NULL, NULL, dns_fixedname_name(&foundname),
1114			       rdataset, sigrdataset);
1115	if (result == DNS_R_NXDOMAIN) {
1116		/*
1117		 * The rdataset and sigrdataset of the relevant NSEC record
1118		 * may be returned, but the caller cannot use them because
1119		 * foundname is not returned by this simplified API.  We
1120		 * disassociate them here to prevent any misuse by the caller.
1121		 */
1122		if (dns_rdataset_isassociated(rdataset))
1123			dns_rdataset_disassociate(rdataset);
1124		if (sigrdataset != NULL &&
1125		    dns_rdataset_isassociated(sigrdataset))
1126			dns_rdataset_disassociate(sigrdataset);
1127	} else if (result != ISC_R_SUCCESS &&
1128		   result != DNS_R_GLUE &&
1129		   result != DNS_R_HINT &&
1130		   result != DNS_R_NCACHENXDOMAIN &&
1131		   result != DNS_R_NCACHENXRRSET &&
1132		   result != DNS_R_NXRRSET &&
1133		   result != DNS_R_HINTNXRRSET &&
1134		   result != ISC_R_NOTFOUND) {
1135		if (dns_rdataset_isassociated(rdataset))
1136			dns_rdataset_disassociate(rdataset);
1137		if (sigrdataset != NULL &&
1138		    dns_rdataset_isassociated(sigrdataset))
1139			dns_rdataset_disassociate(sigrdataset);
1140		result = ISC_R_NOTFOUND;
1141	}
1142
1143	return (result);
1144}
1145
1146isc_result_t
1147dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1148		     isc_stdtime_t now, unsigned int options,
1149		     isc_boolean_t use_hints,
1150		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1151{
1152	return(dns_view_findzonecut2(view, name, fname, now, options,
1153				     use_hints, ISC_TRUE,
1154				     rdataset, sigrdataset));
1155}
1156
1157isc_result_t
1158dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1159		      isc_stdtime_t now, unsigned int options,
1160		      isc_boolean_t use_hints,	isc_boolean_t use_cache,
1161		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1162{
1163	isc_result_t result;
1164	dns_db_t *db;
1165	isc_boolean_t is_cache, use_zone, try_hints;
1166	dns_zone_t *zone;
1167	dns_name_t *zfname;
1168	dns_rdataset_t zrdataset, zsigrdataset;
1169	dns_fixedname_t zfixedname;
1170
1171	REQUIRE(DNS_VIEW_VALID(view));
1172	REQUIRE(view->frozen);
1173
1174	db = NULL;
1175	zone = NULL;
1176	use_zone = ISC_FALSE;
1177	try_hints = ISC_FALSE;
1178	zfname = NULL;
1179
1180	/*
1181	 * Initialize.
1182	 */
1183	dns_fixedname_init(&zfixedname);
1184	dns_rdataset_init(&zrdataset);
1185	dns_rdataset_init(&zsigrdataset);
1186
1187	/*
1188	 * Find the right database.
1189	 */
1190#ifdef BIND9
1191	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1192	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1193		result = dns_zone_getdb(zone, &db);
1194#else
1195	result = ISC_R_NOTFOUND;
1196#endif
1197	if (result == ISC_R_NOTFOUND) {
1198		/*
1199		 * We're not directly authoritative for this query name, nor
1200		 * is it a subdomain of any zone for which we're
1201		 * authoritative.
1202		 */
1203		if (use_cache && view->cachedb != NULL) {
1204			/*
1205			 * We have a cache; try it.
1206			 */
1207			dns_db_attach(view->cachedb, &db);
1208		} else {
1209			/*
1210			 * Maybe we have hints...
1211			 */
1212			try_hints = ISC_TRUE;
1213			goto finish;
1214		}
1215	} else if (result != ISC_R_SUCCESS) {
1216		/*
1217		 * Something is broken.
1218		 */
1219		goto cleanup;
1220	}
1221	is_cache = dns_db_iscache(db);
1222
1223 db_find:
1224	/*
1225	 * Look for the zonecut.
1226	 */
1227	if (!is_cache) {
1228		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1229				     now, NULL, fname, rdataset, sigrdataset);
1230		if (result == DNS_R_DELEGATION)
1231			result = ISC_R_SUCCESS;
1232		else if (result != ISC_R_SUCCESS)
1233			goto cleanup;
1234		if (use_cache && view->cachedb != NULL && db != view->hints) {
1235			/*
1236			 * We found an answer, but the cache may be better.
1237			 */
1238			zfname = dns_fixedname_name(&zfixedname);
1239			result = dns_name_copy(fname, zfname, NULL);
1240			if (result != ISC_R_SUCCESS)
1241				goto cleanup;
1242			dns_rdataset_clone(rdataset, &zrdataset);
1243			dns_rdataset_disassociate(rdataset);
1244			if (sigrdataset != NULL &&
1245			    dns_rdataset_isassociated(sigrdataset)) {
1246				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1247				dns_rdataset_disassociate(sigrdataset);
1248			}
1249			dns_db_detach(&db);
1250			dns_db_attach(view->cachedb, &db);
1251			is_cache = ISC_TRUE;
1252			goto db_find;
1253		}
1254	} else {
1255		result = dns_db_findzonecut(db, name, options, now, NULL,
1256					    fname, rdataset, sigrdataset);
1257		if (result == ISC_R_SUCCESS) {
1258			if (zfname != NULL &&
1259			    (!dns_name_issubdomain(fname, zfname) ||
1260			     (dns_zone_staticstub &&
1261			      dns_name_equal(fname, zfname)))) {
1262				/*
1263				 * We found a zonecut in the cache, but our
1264				 * zone delegation is better.
1265				 */
1266				use_zone = ISC_TRUE;
1267			}
1268		} else if (result == ISC_R_NOTFOUND) {
1269			if (zfname != NULL) {
1270				/*
1271				 * We didn't find anything in the cache, but we
1272				 * have a zone delegation, so use it.
1273				 */
1274				use_zone = ISC_TRUE;
1275			} else {
1276				/*
1277				 * Maybe we have hints...
1278				 */
1279				try_hints = ISC_TRUE;
1280			}
1281		} else {
1282			/*
1283			 * Something bad happened.
1284			 */
1285			goto cleanup;
1286		}
1287	}
1288
1289 finish:
1290	if (use_zone) {
1291		if (dns_rdataset_isassociated(rdataset)) {
1292			dns_rdataset_disassociate(rdataset);
1293			if (sigrdataset != NULL &&
1294			    dns_rdataset_isassociated(sigrdataset))
1295				dns_rdataset_disassociate(sigrdataset);
1296		}
1297		result = dns_name_copy(zfname, fname, NULL);
1298		if (result != ISC_R_SUCCESS)
1299			goto cleanup;
1300		dns_rdataset_clone(&zrdataset, rdataset);
1301		if (sigrdataset != NULL &&
1302		    dns_rdataset_isassociated(&zrdataset))
1303			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1304	} else if (try_hints && use_hints && view->hints != NULL) {
1305		/*
1306		 * We've found nothing so far, but we have hints.
1307		 */
1308		result = dns_db_find(view->hints, dns_rootname, NULL,
1309				     dns_rdatatype_ns, 0, now, NULL, fname,
1310				     rdataset, NULL);
1311		if (result != ISC_R_SUCCESS) {
1312			/*
1313			 * We can't even find the hints for the root
1314			 * nameservers!
1315			 */
1316			if (dns_rdataset_isassociated(rdataset))
1317				dns_rdataset_disassociate(rdataset);
1318			result = ISC_R_NOTFOUND;
1319		}
1320	}
1321
1322 cleanup:
1323	if (dns_rdataset_isassociated(&zrdataset)) {
1324		dns_rdataset_disassociate(&zrdataset);
1325		if (dns_rdataset_isassociated(&zsigrdataset))
1326			dns_rdataset_disassociate(&zsigrdataset);
1327	}
1328	if (db != NULL)
1329		dns_db_detach(&db);
1330#ifdef BIND9
1331	if (zone != NULL)
1332		dns_zone_detach(&zone);
1333#endif
1334
1335	return (result);
1336}
1337
1338isc_result_t
1339dns_viewlist_find(dns_viewlist_t *list, const char *name,
1340		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1341{
1342	dns_view_t *view;
1343
1344	REQUIRE(list != NULL);
1345
1346	for (view = ISC_LIST_HEAD(*list);
1347	     view != NULL;
1348	     view = ISC_LIST_NEXT(view, link)) {
1349		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1350			break;
1351	}
1352	if (view == NULL)
1353		return (ISC_R_NOTFOUND);
1354
1355	dns_view_attach(view, viewp);
1356
1357	return (ISC_R_SUCCESS);
1358}
1359
1360#ifdef BIND9
1361isc_result_t
1362dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1363		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1364		      dns_zone_t **zonep)
1365{
1366	dns_view_t *view;
1367	isc_result_t result;
1368	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1369	dns_zone_t **zp = NULL;;
1370
1371	REQUIRE(list != NULL);
1372	for (view = ISC_LIST_HEAD(*list);
1373	     view != NULL;
1374	     view = ISC_LIST_NEXT(view, link)) {
1375		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1376			continue;
1377
1378		/*
1379		 * If the zone is defined in more than one view,
1380		 * treat it as not found.
1381		 */
1382		zp = (zone1 == NULL) ? &zone1 : &zone2;
1383		result = dns_zt_find(view->zonetable, name, 0, NULL, zp);
1384		INSIST(result == ISC_R_SUCCESS ||
1385		       result == ISC_R_NOTFOUND ||
1386		       result == DNS_R_PARTIALMATCH);
1387
1388		/* Treat a partial match as no match */
1389		if (result == DNS_R_PARTIALMATCH) {
1390			dns_zone_detach(zp);
1391			result = ISC_R_NOTFOUND;
1392			POST(result);
1393		}
1394
1395		if (zone2 != NULL) {
1396			dns_zone_detach(&zone1);
1397			dns_zone_detach(&zone2);
1398			return (ISC_R_NOTFOUND);
1399		}
1400	}
1401
1402	if (zone1 != NULL) {
1403		dns_zone_attach(zone1, zonep);
1404		dns_zone_detach(&zone1);
1405		return (ISC_R_SUCCESS);
1406	}
1407
1408	return (ISC_R_NOTFOUND);
1409}
1410
1411isc_result_t
1412dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1413
1414	REQUIRE(DNS_VIEW_VALID(view));
1415
1416	return (dns_zt_load(view->zonetable, stop));
1417}
1418
1419isc_result_t
1420dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1421
1422	REQUIRE(DNS_VIEW_VALID(view));
1423
1424	return (dns_zt_loadnew(view->zonetable, stop));
1425}
1426#endif /* BIND9 */
1427
1428isc_result_t
1429dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1430{
1431	isc_result_t result;
1432	REQUIRE(keyp != NULL && *keyp == NULL);
1433
1434	result = dns_tsigkey_find(keyp, keyname, NULL,
1435				  view->statickeys);
1436	if (result == ISC_R_NOTFOUND)
1437		result = dns_tsigkey_find(keyp, keyname, NULL,
1438					  view->dynamickeys);
1439	return (result);
1440}
1441
1442isc_result_t
1443dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1444		     dns_tsigkey_t **keyp)
1445{
1446	isc_result_t result;
1447	dns_name_t *keyname = NULL;
1448	dns_peer_t *peer = NULL;
1449
1450	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1451	if (result != ISC_R_SUCCESS)
1452		return (result);
1453
1454	result = dns_peer_getkey(peer, &keyname);
1455	if (result != ISC_R_SUCCESS)
1456		return (result);
1457
1458	result = dns_view_gettsig(view, keyname, keyp);
1459	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1460}
1461
1462isc_result_t
1463dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1464	REQUIRE(DNS_VIEW_VALID(view));
1465	REQUIRE(source != NULL);
1466
1467	return (dns_tsig_verify(source, msg, view->statickeys,
1468				view->dynamickeys));
1469}
1470
1471#ifdef BIND9
1472isc_result_t
1473dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1474	isc_result_t result;
1475
1476	REQUIRE(DNS_VIEW_VALID(view));
1477
1478	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1479	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1480					 &dns_master_style_cache, fp);
1481	if (result != ISC_R_SUCCESS)
1482		return (result);
1483	dns_adb_dump(view->adb, fp);
1484	dns_resolver_printbadcache(view->resolver, fp);
1485	return (ISC_R_SUCCESS);
1486}
1487#endif
1488
1489isc_result_t
1490dns_view_flushcache(dns_view_t *view) {
1491	return (dns_view_flushcache2(view, ISC_FALSE));
1492}
1493
1494isc_result_t
1495dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1496	isc_result_t result;
1497
1498	REQUIRE(DNS_VIEW_VALID(view));
1499
1500	if (view->cachedb == NULL)
1501		return (ISC_R_SUCCESS);
1502	if (!fixuponly) {
1503		result = dns_cache_flush(view->cache);
1504		if (result != ISC_R_SUCCESS)
1505			return (result);
1506	}
1507#ifdef BIND9
1508	if (view->acache != NULL)
1509		dns_acache_putdb(view->acache, view->cachedb);
1510#endif
1511	dns_db_detach(&view->cachedb);
1512	dns_cache_attachdb(view->cache, &view->cachedb);
1513#ifdef BIND9
1514	if (view->acache != NULL)
1515		dns_acache_setdb(view->acache, view->cachedb);
1516	if (view->resolver != NULL)
1517		dns_resolver_flushbadcache(view->resolver, NULL);
1518#endif
1519
1520	dns_adb_flush(view->adb);
1521	return (ISC_R_SUCCESS);
1522}
1523
1524isc_result_t
1525dns_view_flushname(dns_view_t *view, dns_name_t *name) {
1526
1527	REQUIRE(DNS_VIEW_VALID(view));
1528
1529	if (view->adb != NULL)
1530		dns_adb_flushname(view->adb, name);
1531	if (view->cache == NULL)
1532		return (ISC_R_SUCCESS);
1533	if (view->resolver != NULL)
1534		dns_resolver_flushbadcache(view->resolver, name);
1535	return (dns_cache_flushname(view->cache, name));
1536}
1537
1538isc_result_t
1539dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1540	isc_result_t result;
1541	dns_name_t *new;
1542	isc_uint32_t hash;
1543
1544	REQUIRE(DNS_VIEW_VALID(view));
1545
1546	if (view->delonly == NULL) {
1547		view->delonly = isc_mem_get(view->mctx,
1548					    sizeof(dns_namelist_t) *
1549					    DNS_VIEW_DELONLYHASH);
1550		if (view->delonly == NULL)
1551			return (ISC_R_NOMEMORY);
1552		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1553			ISC_LIST_INIT(view->delonly[hash]);
1554	}
1555	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1556	new = ISC_LIST_HEAD(view->delonly[hash]);
1557	while (new != NULL && !dns_name_equal(new, name))
1558		new = ISC_LIST_NEXT(new, link);
1559	if (new != NULL)
1560		return (ISC_R_SUCCESS);
1561	new = isc_mem_get(view->mctx, sizeof(*new));
1562	if (new == NULL)
1563		return (ISC_R_NOMEMORY);
1564	dns_name_init(new, NULL);
1565	result = dns_name_dup(name, view->mctx, new);
1566	if (result == ISC_R_SUCCESS)
1567		ISC_LIST_APPEND(view->delonly[hash], new, link);
1568	else
1569		isc_mem_put(view->mctx, new, sizeof(*new));
1570	return (result);
1571}
1572
1573isc_result_t
1574dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1575	isc_result_t result;
1576	dns_name_t *new;
1577	isc_uint32_t hash;
1578
1579	REQUIRE(DNS_VIEW_VALID(view));
1580
1581	if (view->rootexclude == NULL) {
1582		view->rootexclude = isc_mem_get(view->mctx,
1583					    sizeof(dns_namelist_t) *
1584					    DNS_VIEW_DELONLYHASH);
1585		if (view->rootexclude == NULL)
1586			return (ISC_R_NOMEMORY);
1587		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1588			ISC_LIST_INIT(view->rootexclude[hash]);
1589	}
1590	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1591	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1592	while (new != NULL && !dns_name_equal(new, name))
1593		new = ISC_LIST_NEXT(new, link);
1594	if (new != NULL)
1595		return (ISC_R_SUCCESS);
1596	new = isc_mem_get(view->mctx, sizeof(*new));
1597	if (new == NULL)
1598		return (ISC_R_NOMEMORY);
1599	dns_name_init(new, NULL);
1600	result = dns_name_dup(name, view->mctx, new);
1601	if (result == ISC_R_SUCCESS)
1602		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1603	else
1604		isc_mem_put(view->mctx, new, sizeof(*new));
1605	return (result);
1606}
1607
1608isc_boolean_t
1609dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1610	dns_name_t *new;
1611	isc_uint32_t hash;
1612
1613	REQUIRE(DNS_VIEW_VALID(view));
1614
1615	if (!view->rootdelonly && view->delonly == NULL)
1616		return (ISC_FALSE);
1617
1618	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1619	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1620		if (view->rootexclude == NULL)
1621			return (ISC_TRUE);
1622		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1623		while (new != NULL && !dns_name_equal(new, name))
1624			new = ISC_LIST_NEXT(new, link);
1625		if (new == NULL)
1626			return (ISC_TRUE);
1627	}
1628
1629	if (view->delonly == NULL)
1630		return (ISC_FALSE);
1631
1632	new = ISC_LIST_HEAD(view->delonly[hash]);
1633	while (new != NULL && !dns_name_equal(new, name))
1634		new = ISC_LIST_NEXT(new, link);
1635	if (new == NULL)
1636		return (ISC_FALSE);
1637	return (ISC_TRUE);
1638}
1639
1640void
1641dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1642	REQUIRE(DNS_VIEW_VALID(view));
1643	view->rootdelonly = value;
1644}
1645
1646isc_boolean_t
1647dns_view_getrootdelonly(dns_view_t *view) {
1648	REQUIRE(DNS_VIEW_VALID(view));
1649	return (view->rootdelonly);
1650}
1651
1652#ifdef BIND9
1653isc_result_t
1654dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1655	REQUIRE(DNS_VIEW_VALID(view));
1656	return (dns_zt_freezezones(view->zonetable, value));
1657}
1658#endif
1659
1660void
1661dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1662	REQUIRE(DNS_VIEW_VALID(view));
1663	REQUIRE(!view->frozen);
1664	REQUIRE(view->resstats == NULL);
1665
1666	isc_stats_attach(stats, &view->resstats);
1667}
1668
1669void
1670dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1671	REQUIRE(DNS_VIEW_VALID(view));
1672	REQUIRE(statsp != NULL && *statsp == NULL);
1673
1674	if (view->resstats != NULL)
1675		isc_stats_attach(view->resstats, statsp);
1676}
1677
1678void
1679dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1680	REQUIRE(DNS_VIEW_VALID(view));
1681	REQUIRE(!view->frozen);
1682	REQUIRE(view->resquerystats == NULL);
1683
1684	dns_stats_attach(stats, &view->resquerystats);
1685}
1686
1687void
1688dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1689	REQUIRE(DNS_VIEW_VALID(view));
1690	REQUIRE(statsp != NULL && *statsp == NULL);
1691
1692	if (view->resquerystats != NULL)
1693		dns_stats_attach(view->resquerystats, statsp);
1694}
1695
1696isc_result_t
1697dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1698	REQUIRE(DNS_VIEW_VALID(view));
1699	if (view->secroots_priv != NULL)
1700		dns_keytable_detach(&view->secroots_priv);
1701	return (dns_keytable_create(mctx, &view->secroots_priv));
1702}
1703
1704isc_result_t
1705dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1706	REQUIRE(DNS_VIEW_VALID(view));
1707	REQUIRE(ktp != NULL && *ktp == NULL);
1708	if (view->secroots_priv == NULL)
1709		return (ISC_R_NOTFOUND);
1710	dns_keytable_attach(view->secroots_priv, ktp);
1711	return (ISC_R_SUCCESS);
1712}
1713
1714isc_result_t
1715dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1716			 isc_boolean_t *secure_domain) {
1717	REQUIRE(DNS_VIEW_VALID(view));
1718
1719	if (view->secroots_priv == NULL)
1720		return (ISC_R_NOTFOUND);
1721	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1722					    secure_domain));
1723}
1724
1725void
1726dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1727		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1728{
1729	isc_result_t result;
1730	unsigned char data[4096];
1731	dns_rdata_t rdata = DNS_RDATA_INIT;
1732	isc_buffer_t buffer;
1733	dst_key_t *key = NULL;
1734	dns_keytable_t *sr = NULL;
1735
1736	/*
1737	 * Clear the revoke bit, if set, so that the key will match what's
1738	 * in secroots now.
1739	 */
1740	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1741
1742	/* Convert dnskey to DST key. */
1743	isc_buffer_init(&buffer, data, sizeof(data));
1744	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1745			     dns_rdatatype_dnskey, dnskey, &buffer);
1746	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1747	if (result != ISC_R_SUCCESS)
1748		return;
1749	result = dns_view_getsecroots(view, &sr);
1750	if (result == ISC_R_SUCCESS) {
1751		dns_keytable_deletekeynode(sr, key);
1752		dns_keytable_detach(&sr);
1753	}
1754	dst_key_free(&key);
1755}
1756
1757#define NZF ".nzf"
1758
1759void
1760dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1761		     void (*cfg_destroy)(void **))
1762{
1763	REQUIRE(DNS_VIEW_VALID(view));
1764	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1765
1766#ifdef BIND9
1767	if (view->new_zone_file != NULL) {
1768		isc_mem_free(view->mctx, view->new_zone_file);
1769		view->new_zone_file = NULL;
1770	}
1771
1772	if (view->new_zone_config != NULL) {
1773		view->cfg_destroy(&view->new_zone_config);
1774		view->cfg_destroy = NULL;
1775	}
1776
1777	if (allow) {
1778		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1779		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1780		/* Truncate the hash at 16 chars; full length is overkill */
1781		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1782		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1783		view->new_zone_config = cfgctx;
1784		view->cfg_destroy = cfg_destroy;
1785	}
1786#else
1787	UNUSED(allow);
1788	UNUSED(cfgctx);
1789	UNUSED(cfg_destroy);
1790#endif
1791}
1792