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