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