1/*
2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/file.h>
25#include <isc/hash.h>
26#include <isc/print.h>
27#include <isc/sha2.h>
28#include <isc/stats.h>
29#include <isc/string.h>		/* Required for HP/UX (and others?) */
30#include <isc/task.h>
31#include <isc/util.h>
32
33#include <dns/acache.h>
34#include <dns/acl.h>
35#include <dns/adb.h>
36#include <dns/cache.h>
37#include <dns/db.h>
38#include <dns/dlz.h>
39#ifdef BIND9
40#include <dns/dns64.h>
41#endif
42#include <dns/dnssec.h>
43#include <dns/events.h>
44#include <dns/forward.h>
45#include <dns/keytable.h>
46#include <dns/keyvalues.h>
47#include <dns/master.h>
48#include <dns/masterdump.h>
49#include <dns/order.h>
50#include <dns/peer.h>
51#include <dns/rbt.h>
52#include <dns/rdataset.h>
53#include <dns/request.h>
54#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	dns_fixedname_init(&view->dlv_fixed);
197	view->managed_keys = NULL;
198#ifdef BIND9
199	view->new_zone_file = NULL;
200	view->new_zone_config = NULL;
201	view->cfg_destroy = NULL;
202
203	result = dns_order_create(view->mctx, &view->order);
204	if (result != ISC_R_SUCCESS)
205		goto cleanup_dynkeys;
206#endif
207
208	result = dns_peerlist_new(view->mctx, &view->peers);
209	if (result != ISC_R_SUCCESS)
210		goto cleanup_order;
211
212	result = dns_aclenv_init(view->mctx, &view->aclenv);
213	if (result != ISC_R_SUCCESS)
214		goto cleanup_peerlist;
215
216	ISC_LINK_INIT(view, link);
217	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
218		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
219		       view, NULL, NULL, NULL);
220	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
221		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
222		       view, NULL, NULL, NULL);
223	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
224		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
225		       view, NULL, NULL, NULL);
226	view->magic = DNS_VIEW_MAGIC;
227
228	*viewp = view;
229
230	return (ISC_R_SUCCESS);
231
232 cleanup_peerlist:
233	dns_peerlist_detach(&view->peers);
234
235 cleanup_order:
236#ifdef BIND9
237	dns_order_detach(&view->order);
238
239 cleanup_dynkeys:
240#endif
241	dns_tsigkeyring_detach(&view->dynamickeys);
242
243 cleanup_references:
244	isc_refcount_destroy(&view->references);
245
246 cleanup_fwdtable:
247	dns_fwdtable_destroy(&view->fwdtable);
248
249 cleanup_zt:
250#ifdef BIND9
251	dns_zt_detach(&view->zonetable);
252
253 cleanup_mutex:
254#endif
255	DESTROYLOCK(&view->lock);
256
257 cleanup_name:
258	isc_mem_free(mctx, view->name);
259
260 cleanup_view:
261	isc_mem_put(mctx, view, sizeof(*view));
262
263	return (result);
264}
265
266static inline void
267destroy(dns_view_t *view) {
268#ifdef BIND9
269	dns_dns64_t *dns64;
270#endif
271
272	REQUIRE(!ISC_LINK_LINKED(view, link));
273	REQUIRE(isc_refcount_current(&view->references) == 0);
274	REQUIRE(view->weakrefs == 0);
275	REQUIRE(RESSHUTDOWN(view));
276	REQUIRE(ADBSHUTDOWN(view));
277	REQUIRE(REQSHUTDOWN(view));
278
279#ifdef BIND9
280	if (view->order != NULL)
281		dns_order_detach(&view->order);
282#endif
283	if (view->peers != NULL)
284		dns_peerlist_detach(&view->peers);
285
286	if (view->dynamickeys != NULL) {
287		isc_result_t result;
288		char template[20];
289		char keyfile[20];
290		FILE *fp = NULL;
291		int n;
292
293		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
294			     view->name);
295		if (n > 0 && (size_t)n < sizeof(keyfile)) {
296			result = isc_file_mktemplate(keyfile, template,
297						     sizeof(template));
298			if (result == ISC_R_SUCCESS)
299				(void)isc_file_openuniqueprivate(template, &fp);
300		}
301		if (fp == NULL)
302			dns_tsigkeyring_detach(&view->dynamickeys);
303		else {
304			result = dns_tsigkeyring_dumpanddetach(
305							&view->dynamickeys, fp);
306			if (result == ISC_R_SUCCESS) {
307				if (fclose(fp) == 0)
308					result = isc_file_rename(template,
309								 keyfile);
310				if (result != ISC_R_SUCCESS)
311					(void)remove(template);
312			} else {
313				(void)fclose(fp);
314				(void)remove(template);
315			}
316		}
317	}
318	if (view->statickeys != NULL)
319		dns_tsigkeyring_detach(&view->statickeys);
320	if (view->adb != NULL)
321		dns_adb_detach(&view->adb);
322	if (view->resolver != NULL)
323		dns_resolver_detach(&view->resolver);
324#ifdef BIND9
325	if (view->acache != NULL) {
326		if (view->cachedb != NULL)
327			dns_acache_putdb(view->acache, view->cachedb);
328		dns_acache_detach(&view->acache);
329	}
330	dns_rpz_view_destroy(view);
331#else
332	INSIST(view->acache == NULL);
333	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
334#endif
335	if (view->requestmgr != NULL)
336		dns_requestmgr_detach(&view->requestmgr);
337	if (view->task != NULL)
338		isc_task_detach(&view->task);
339	if (view->hints != NULL)
340		dns_db_detach(&view->hints);
341	if (view->dlzdatabase != NULL)
342		dns_dlzdestroy(&view->dlzdatabase);
343	if (view->cachedb != NULL)
344		dns_db_detach(&view->cachedb);
345	if (view->cache != NULL)
346		dns_cache_detach(&view->cache);
347	if (view->matchclients != NULL)
348		dns_acl_detach(&view->matchclients);
349	if (view->matchdestinations != NULL)
350		dns_acl_detach(&view->matchdestinations);
351	if (view->cacheacl != NULL)
352		dns_acl_detach(&view->cacheacl);
353	if (view->cacheonacl != NULL)
354		dns_acl_detach(&view->cacheonacl);
355	if (view->queryacl != NULL)
356		dns_acl_detach(&view->queryacl);
357	if (view->queryonacl != NULL)
358		dns_acl_detach(&view->queryonacl);
359	if (view->recursionacl != NULL)
360		dns_acl_detach(&view->recursionacl);
361	if (view->recursiononacl != NULL)
362		dns_acl_detach(&view->recursiononacl);
363	if (view->sortlist != NULL)
364		dns_acl_detach(&view->sortlist);
365	if (view->transferacl != NULL)
366		dns_acl_detach(&view->transferacl);
367	if (view->notifyacl != NULL)
368		dns_acl_detach(&view->notifyacl);
369	if (view->updateacl != NULL)
370		dns_acl_detach(&view->updateacl);
371	if (view->upfwdacl != NULL)
372		dns_acl_detach(&view->upfwdacl);
373	if (view->denyansweracl != NULL)
374		dns_acl_detach(&view->denyansweracl);
375	if (view->v4_aaaa_acl != NULL)
376		dns_acl_detach(&view->v4_aaaa_acl);
377	if (view->answeracl_exclude != NULL)
378		dns_rbt_destroy(&view->answeracl_exclude);
379	if (view->denyanswernames != NULL)
380		dns_rbt_destroy(&view->denyanswernames);
381	if (view->answernames_exclude != NULL)
382		dns_rbt_destroy(&view->answernames_exclude);
383	if (view->delonly != NULL) {
384		dns_name_t *name;
385		int i;
386
387		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
388			name = ISC_LIST_HEAD(view->delonly[i]);
389			while (name != NULL) {
390				ISC_LIST_UNLINK(view->delonly[i], name, link);
391				dns_name_free(name, view->mctx);
392				isc_mem_put(view->mctx, name, sizeof(*name));
393				name = ISC_LIST_HEAD(view->delonly[i]);
394			}
395		}
396		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
397			    DNS_VIEW_DELONLYHASH);
398		view->delonly = NULL;
399	}
400	if (view->rootexclude != NULL) {
401		dns_name_t *name;
402		int i;
403
404		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
405			name = ISC_LIST_HEAD(view->rootexclude[i]);
406			while (name != NULL) {
407				ISC_LIST_UNLINK(view->rootexclude[i],
408						name, link);
409				dns_name_free(name, view->mctx);
410				isc_mem_put(view->mctx, name, sizeof(*name));
411				name = ISC_LIST_HEAD(view->rootexclude[i]);
412			}
413		}
414		isc_mem_put(view->mctx, view->rootexclude,
415			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
416		view->rootexclude = NULL;
417	}
418	if (view->resstats != NULL)
419		isc_stats_detach(&view->resstats);
420	if (view->resquerystats != NULL)
421		dns_stats_detach(&view->resquerystats);
422	if (view->secroots_priv != NULL)
423		dns_keytable_detach(&view->secroots_priv);
424#ifdef BIND9
425	for (dns64 = ISC_LIST_HEAD(view->dns64);
426	     dns64 != NULL;
427	     dns64 = ISC_LIST_HEAD(view->dns64)) {
428		dns_dns64_unlink(&view->dns64, dns64);
429		dns_dns64_destroy(&dns64);
430	}
431	if (view->managed_keys != NULL)
432		dns_zone_detach(&view->managed_keys);
433	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
434#endif
435	dns_fwdtable_destroy(&view->fwdtable);
436	dns_aclenv_destroy(&view->aclenv);
437	DESTROYLOCK(&view->lock);
438	isc_refcount_destroy(&view->references);
439	isc_mem_free(view->mctx, view->name);
440	isc_mem_put(view->mctx, view, sizeof(*view));
441}
442
443/*
444 * Return true iff 'view' may be freed.
445 * The caller must be holding the view lock.
446 */
447static isc_boolean_t
448all_done(dns_view_t *view) {
449
450	if (isc_refcount_current(&view->references) == 0 &&
451	    view->weakrefs == 0 &&
452	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
453		return (ISC_TRUE);
454
455	return (ISC_FALSE);
456}
457
458void
459dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
460
461	REQUIRE(DNS_VIEW_VALID(source));
462	REQUIRE(targetp != NULL && *targetp == NULL);
463
464	isc_refcount_increment(&source->references, NULL);
465
466	*targetp = source;
467}
468
469static void
470view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
471	dns_view_t *view;
472	unsigned int refs;
473	isc_boolean_t done = ISC_FALSE;
474
475	REQUIRE(viewp != NULL);
476	view = *viewp;
477	REQUIRE(DNS_VIEW_VALID(view));
478
479	if (flush)
480		view->flush = ISC_TRUE;
481	isc_refcount_decrement(&view->references, &refs);
482	if (refs == 0) {
483		LOCK(&view->lock);
484		if (!RESSHUTDOWN(view))
485			dns_resolver_shutdown(view->resolver);
486		if (!ADBSHUTDOWN(view))
487			dns_adb_shutdown(view->adb);
488		if (!REQSHUTDOWN(view))
489			dns_requestmgr_shutdown(view->requestmgr);
490#ifdef BIND9
491		if (view->acache != NULL)
492			dns_acache_shutdown(view->acache);
493		if (view->flush)
494			dns_zt_flushanddetach(&view->zonetable);
495		else
496			dns_zt_detach(&view->zonetable);
497		if (view->managed_keys != NULL) {
498			if (view->flush)
499				dns_zone_flush(view->managed_keys);
500			dns_zone_detach(&view->managed_keys);
501		}
502#endif
503		done = all_done(view);
504		UNLOCK(&view->lock);
505	}
506
507	*viewp = NULL;
508
509	if (done)
510		destroy(view);
511}
512
513void
514dns_view_flushanddetach(dns_view_t **viewp) {
515	view_flushanddetach(viewp, ISC_TRUE);
516}
517
518void
519dns_view_detach(dns_view_t **viewp) {
520	view_flushanddetach(viewp, ISC_FALSE);
521}
522
523#ifdef BIND9
524static isc_result_t
525dialup(dns_zone_t *zone, void *dummy) {
526	UNUSED(dummy);
527	dns_zone_dialup(zone);
528	return (ISC_R_SUCCESS);
529}
530
531void
532dns_view_dialup(dns_view_t *view) {
533	REQUIRE(DNS_VIEW_VALID(view));
534	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
535}
536#endif
537
538void
539dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
540
541	REQUIRE(DNS_VIEW_VALID(source));
542	REQUIRE(targetp != NULL && *targetp == NULL);
543
544	LOCK(&source->lock);
545	source->weakrefs++;
546	UNLOCK(&source->lock);
547
548	*targetp = source;
549}
550
551void
552dns_view_weakdetach(dns_view_t **viewp) {
553	dns_view_t *view;
554	isc_boolean_t done = ISC_FALSE;
555
556	REQUIRE(viewp != NULL);
557	view = *viewp;
558	REQUIRE(DNS_VIEW_VALID(view));
559
560	LOCK(&view->lock);
561
562	INSIST(view->weakrefs > 0);
563	view->weakrefs--;
564	done = all_done(view);
565
566	UNLOCK(&view->lock);
567
568	*viewp = NULL;
569
570	if (done)
571		destroy(view);
572}
573
574static void
575resolver_shutdown(isc_task_t *task, isc_event_t *event) {
576	dns_view_t *view = event->ev_arg;
577	isc_boolean_t done;
578
579	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
580	REQUIRE(DNS_VIEW_VALID(view));
581	REQUIRE(view->task == task);
582
583	UNUSED(task);
584
585	LOCK(&view->lock);
586
587	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
588	done = all_done(view);
589
590	UNLOCK(&view->lock);
591
592	isc_event_free(&event);
593
594	if (done)
595		destroy(view);
596}
597
598static void
599adb_shutdown(isc_task_t *task, isc_event_t *event) {
600	dns_view_t *view = event->ev_arg;
601	isc_boolean_t done;
602
603	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
604	REQUIRE(DNS_VIEW_VALID(view));
605	REQUIRE(view->task == task);
606
607	UNUSED(task);
608
609	LOCK(&view->lock);
610
611	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
612	done = all_done(view);
613
614	UNLOCK(&view->lock);
615
616	isc_event_free(&event);
617
618	if (done)
619		destroy(view);
620}
621
622static void
623req_shutdown(isc_task_t *task, isc_event_t *event) {
624	dns_view_t *view = event->ev_arg;
625	isc_boolean_t done;
626
627	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
628	REQUIRE(DNS_VIEW_VALID(view));
629	REQUIRE(view->task == task);
630
631	UNUSED(task);
632
633	LOCK(&view->lock);
634
635	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
636	done = all_done(view);
637
638	UNLOCK(&view->lock);
639
640	isc_event_free(&event);
641
642	if (done)
643		destroy(view);
644}
645
646isc_result_t
647dns_view_createresolver(dns_view_t *view,
648			isc_taskmgr_t *taskmgr, unsigned int ntasks,
649			isc_socketmgr_t *socketmgr,
650			isc_timermgr_t *timermgr,
651			unsigned int options,
652			dns_dispatchmgr_t *dispatchmgr,
653			dns_dispatch_t *dispatchv4,
654			dns_dispatch_t *dispatchv6)
655{
656	isc_result_t result;
657	isc_event_t *event;
658	isc_mem_t *mctx = NULL;
659
660	REQUIRE(DNS_VIEW_VALID(view));
661	REQUIRE(!view->frozen);
662	REQUIRE(view->resolver == NULL);
663
664	result = isc_task_create(taskmgr, 0, &view->task);
665	if (result != ISC_R_SUCCESS)
666		return (result);
667	isc_task_setname(view->task, "view", view);
668
669	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
670				     timermgr, options, dispatchmgr,
671				     dispatchv4, dispatchv6,
672				     &view->resolver);
673	if (result != ISC_R_SUCCESS) {
674		isc_task_detach(&view->task);
675		return (result);
676	}
677	event = &view->resevent;
678	dns_resolver_whenshutdown(view->resolver, view->task, &event);
679	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
680
681	result = isc_mem_create(0, 0, &mctx);
682	if (result != ISC_R_SUCCESS) {
683		dns_resolver_shutdown(view->resolver);
684		return (result);
685	}
686
687	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
688	isc_mem_setname(mctx, "ADB", NULL);
689	isc_mem_detach(&mctx);
690	if (result != ISC_R_SUCCESS) {
691		dns_resolver_shutdown(view->resolver);
692		return (result);
693	}
694	event = &view->adbevent;
695	dns_adb_whenshutdown(view->adb, view->task, &event);
696	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
697
698	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
699				      dns_resolver_taskmgr(view->resolver),
700				      dns_resolver_dispatchmgr(view->resolver),
701				      dns_resolver_dispatchv4(view->resolver),
702				      dns_resolver_dispatchv6(view->resolver),
703				      &view->requestmgr);
704	if (result != ISC_R_SUCCESS) {
705		dns_adb_shutdown(view->adb);
706		dns_resolver_shutdown(view->resolver);
707		return (result);
708	}
709	event = &view->reqevent;
710	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
711	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
712
713	return (ISC_R_SUCCESS);
714}
715
716void
717dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
718	dns_view_setcache2(view, cache, ISC_FALSE);
719}
720
721void
722dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
723	REQUIRE(DNS_VIEW_VALID(view));
724	REQUIRE(!view->frozen);
725
726	view->cacheshared = shared;
727	if (view->cache != NULL) {
728#ifdef BIND9
729		if (view->acache != NULL)
730			dns_acache_putdb(view->acache, view->cachedb);
731#endif
732		dns_db_detach(&view->cachedb);
733		dns_cache_detach(&view->cache);
734	}
735	dns_cache_attach(cache, &view->cache);
736	dns_cache_attachdb(cache, &view->cachedb);
737	INSIST(DNS_DB_VALID(view->cachedb));
738
739#ifdef BIND9
740	if (view->acache != NULL)
741		dns_acache_setdb(view->acache, view->cachedb);
742#endif
743}
744
745isc_boolean_t
746dns_view_iscacheshared(dns_view_t *view) {
747	REQUIRE(DNS_VIEW_VALID(view));
748
749	return (view->cacheshared);
750}
751
752void
753dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
754	REQUIRE(DNS_VIEW_VALID(view));
755	REQUIRE(!view->frozen);
756	REQUIRE(view->hints == NULL);
757	REQUIRE(dns_db_iszone(hints));
758
759	dns_db_attach(hints, &view->hints);
760}
761
762void
763dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
764	REQUIRE(DNS_VIEW_VALID(view));
765	REQUIRE(ring != NULL);
766	if (view->statickeys != NULL)
767		dns_tsigkeyring_detach(&view->statickeys);
768	dns_tsigkeyring_attach(ring, &view->statickeys);
769}
770
771void
772dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
773	REQUIRE(DNS_VIEW_VALID(view));
774	REQUIRE(ring != NULL);
775	if (view->dynamickeys != NULL)
776		dns_tsigkeyring_detach(&view->dynamickeys);
777	dns_tsigkeyring_attach(ring, &view->dynamickeys);
778}
779
780void
781dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
782	REQUIRE(DNS_VIEW_VALID(view));
783	REQUIRE(ringp != NULL && *ringp == NULL);
784	if (view->dynamickeys != NULL)
785		dns_tsigkeyring_attach(view->dynamickeys, ringp);
786}
787
788void
789dns_view_restorekeyring(dns_view_t *view) {
790	FILE *fp;
791	char keyfile[20];
792	int n;
793
794	REQUIRE(DNS_VIEW_VALID(view));
795
796	if (view->dynamickeys != NULL) {
797		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
798			     view->name);
799		if (n > 0 && (size_t)n < sizeof(keyfile)) {
800			fp = fopen(keyfile, "r");
801			if (fp != NULL) {
802				dns_keyring_restore(view->dynamickeys, fp);
803				(void)fclose(fp);
804			}
805		}
806	}
807}
808
809void
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
1717	if (view->secroots_priv == NULL)
1718		return (ISC_R_NOTFOUND);
1719	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1720					    secure_domain));
1721}
1722
1723void
1724dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1725		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1726{
1727	isc_result_t result;
1728	unsigned char data[4096];
1729	dns_rdata_t rdata = DNS_RDATA_INIT;
1730	isc_buffer_t buffer;
1731	dst_key_t *key = NULL;
1732	dns_keytable_t *sr = NULL;
1733
1734	/*
1735	 * Clear the revoke bit, if set, so that the key will match what's
1736	 * in secroots now.
1737	 */
1738	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1739
1740	/* Convert dnskey to DST key. */
1741	isc_buffer_init(&buffer, data, sizeof(data));
1742	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1743			     dns_rdatatype_dnskey, dnskey, &buffer);
1744	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1745	if (result != ISC_R_SUCCESS)
1746		return;
1747	result = dns_view_getsecroots(view, &sr);
1748	if (result == ISC_R_SUCCESS) {
1749		dns_keytable_deletekeynode(sr, key);
1750		dns_keytable_detach(&sr);
1751	}
1752	dst_key_free(&key);
1753}
1754
1755#define NZF ".nzf"
1756
1757void
1758dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1759		     void (*cfg_destroy)(void **))
1760{
1761	REQUIRE(DNS_VIEW_VALID(view));
1762	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1763
1764#ifdef BIND9
1765	if (view->new_zone_file != NULL) {
1766		isc_mem_free(view->mctx, view->new_zone_file);
1767		view->new_zone_file = NULL;
1768	}
1769
1770	if (view->new_zone_config != NULL) {
1771		view->cfg_destroy(&view->new_zone_config);
1772		view->cfg_destroy = NULL;
1773	}
1774
1775	if (allow) {
1776		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1777		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1778		/* Truncate the hash at 16 chars; full length is overkill */
1779		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1780		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1781		view->new_zone_config = cfgctx;
1782		view->cfg_destroy = cfg_destroy;
1783	}
1784#else
1785	UNUSED(allow);
1786	UNUSED(cfgctx);
1787	UNUSED(cfg_destroy);
1788#endif
1789}
1790