xref: /netbsd/external/mpl/bind/dist/lib/dns/view.c (revision 0377c12b)
1 /*	$NetBSD: view.c,v 1.2 2018/08/12 13:02:35 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <config.h>
17 
18 #include <limits.h>
19 
20 #ifdef HAVE_LMDB
21  #include <lmdb.h>
22 #endif
23 
24 #include <isc/file.h>
25 #include <isc/hash.h>
26 #include <isc/lex.h>
27 #include <isc/print.h>
28 #include <isc/sha2.h>
29 #include <isc/stats.h>
30 #include <isc/string.h>		/* Required for HP/UX (and others?) */
31 #include <isc/task.h>
32 #include <isc/util.h>
33 
34 #include <dns/acl.h>
35 #include <dns/adb.h>
36 #include <dns/badcache.h>
37 #include <dns/cache.h>
38 #include <dns/db.h>
39 #include <dns/dispatch.h>
40 #include <dns/dlz.h>
41 #include <dns/dns64.h>
42 #include <dns/dnssec.h>
43 #include <dns/events.h>
44 #include <dns/forward.h>
45 #include <dns/keytable.h>
46 #include <dns/keyvalues.h>
47 #include <dns/master.h>
48 #include <dns/masterdump.h>
49 #include <dns/nta.h>
50 #include <dns/order.h>
51 #include <dns/peer.h>
52 #include <dns/rbt.h>
53 #include <dns/rdataset.h>
54 #include <dns/request.h>
55 #include <dns/resolver.h>
56 #include <dns/result.h>
57 #include <dns/rpz.h>
58 #include <dns/rrl.h>
59 #include <dns/stats.h>
60 #include <dns/time.h>
61 #include <dns/tsig.h>
62 #include <dns/zone.h>
63 #include <dns/zt.h>
64 
65 #define CHECK(op) \
66 	do { result = (op);					 \
67 	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
68 	} while (0)
69 
70 #define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
71 #define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
72 #define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
73 
74 #define DNS_VIEW_DELONLYHASH 111
75 #define DNS_VIEW_FAILCACHESIZE 1021
76 
77 static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
78 static void adb_shutdown(isc_task_t *task, isc_event_t *event);
79 static void req_shutdown(isc_task_t *task, isc_event_t *event);
80 
81 isc_result_t
82 dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
83 		const char *name, dns_view_t **viewp)
84 {
85 	dns_view_t *view;
86 	isc_result_t result;
87 	char buffer[1024];
88 
89 	/*
90 	 * Create a view.
91 	 */
92 
93 	REQUIRE(name != NULL);
94 	REQUIRE(viewp != NULL && *viewp == NULL);
95 
96 	view = isc_mem_get(mctx, sizeof(*view));
97 	if (view == NULL)
98 		return (ISC_R_NOMEMORY);
99 
100 	view->nta_file = NULL;
101 	view->mctx = NULL;
102 	isc_mem_attach(mctx, &view->mctx);
103 	view->name = isc_mem_strdup(mctx, name);
104 	if (view->name == NULL) {
105 		result = ISC_R_NOMEMORY;
106 		goto cleanup_view;
107 	}
108 
109 	result = isc_file_sanitize(NULL, view->name, "nta",
110 				   buffer, sizeof(buffer));
111 	if (result != ISC_R_SUCCESS)
112 		goto cleanup_name;
113 	view->nta_file = isc_mem_strdup(mctx, buffer);
114 	if (view->nta_file == NULL) {
115 		result = ISC_R_NOMEMORY;
116 		goto cleanup_name;
117 	}
118 
119 	result = isc_mutex_init(&view->lock);
120 	if (result != ISC_R_SUCCESS)
121 		goto cleanup_name;
122 
123 	view->zonetable = NULL;
124 	if (isc_bind9) {
125 		result = dns_zt_create(mctx, rdclass, &view->zonetable);
126 		if (result != ISC_R_SUCCESS) {
127 			UNEXPECTED_ERROR(__FILE__, __LINE__,
128 					 "dns_zt_create() failed: %s",
129 					 isc_result_totext(result));
130 			result = ISC_R_UNEXPECTED;
131 			goto cleanup_mutex;
132 		}
133 	}
134 	view->secroots_priv = NULL;
135 	view->ntatable_priv = NULL;
136 	view->fwdtable = NULL;
137 	result = dns_fwdtable_create(mctx, &view->fwdtable);
138 	if (result != ISC_R_SUCCESS) {
139 		UNEXPECTED_ERROR(__FILE__, __LINE__,
140 				 "dns_fwdtable_create() failed: %s",
141 				 isc_result_totext(result));
142 		result = ISC_R_UNEXPECTED;
143 		goto cleanup_zt;
144 	}
145 
146 	view->cache = NULL;
147 	view->cachedb = NULL;
148 	ISC_LIST_INIT(view->dlz_searched);
149 	ISC_LIST_INIT(view->dlz_unsearched);
150 	view->hints = NULL;
151 	view->resolver = NULL;
152 	view->adb = NULL;
153 	view->requestmgr = NULL;
154 	view->rdclass = rdclass;
155 	view->frozen = ISC_FALSE;
156 	view->task = NULL;
157 	result = isc_refcount_init(&view->references, 1);
158 	if (result != ISC_R_SUCCESS)
159 		goto cleanup_fwdtable;
160 	view->weakrefs = 0;
161 	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
162 			    DNS_VIEWATTR_REQSHUTDOWN);
163 	view->statickeys = NULL;
164 	view->dynamickeys = NULL;
165 	view->matchclients = NULL;
166 	view->matchdestinations = NULL;
167 	view->matchrecursiveonly = ISC_FALSE;
168 	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
169 	if (result != ISC_R_SUCCESS)
170 		goto cleanup_references;
171 	view->peers = NULL;
172 	view->order = NULL;
173 	view->delonly = NULL;
174 	view->rootdelonly = ISC_FALSE;
175 	view->rootexclude = NULL;
176 	view->adbstats = NULL;
177 	view->resstats = NULL;
178 	view->resquerystats = NULL;
179 	view->cacheshared = ISC_FALSE;
180 	ISC_LIST_INIT(view->dns64);
181 	view->dns64cnt = 0;
182 
183 	/*
184 	 * Initialize configuration data with default values.
185 	 */
186 	view->recursion = ISC_TRUE;
187 	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
188 	view->enablednssec = ISC_TRUE;
189 	view->enablevalidation = ISC_TRUE;
190 	view->acceptexpired = ISC_FALSE;
191 	view->use_glue_cache = ISC_FALSE;
192 	view->minimal_any = ISC_FALSE;
193 	view->minimalresponses = dns_minimal_no;
194 	view->transfer_format = dns_one_answer;
195 	view->cacheacl = NULL;
196 	view->cacheonacl = NULL;
197 	view->queryacl = NULL;
198 	view->queryonacl = NULL;
199 	view->recursionacl = NULL;
200 	view->recursiononacl = NULL;
201 	view->sortlist = NULL;
202 	view->transferacl = NULL;
203 	view->notifyacl = NULL;
204 	view->updateacl = NULL;
205 	view->upfwdacl = NULL;
206 	view->denyansweracl = NULL;
207 	view->nocasecompress = NULL;
208 	view->msgcompression = ISC_TRUE;
209 	view->answeracl_exclude = NULL;
210 	view->denyanswernames = NULL;
211 	view->answernames_exclude = NULL;
212 	view->rrl = NULL;
213 	view->provideixfr = ISC_TRUE;
214 	view->maxcachettl = 7 * 24 * 3600;
215 	view->maxncachettl = 3 * 3600;
216 	view->nta_lifetime = 0;
217 	view->nta_recheck = 0;
218 	view->prefetch_eligible = 0;
219 	view->prefetch_trigger = 0;
220 	view->dstport = 53;
221 	view->preferred_glue = 0;
222 	view->flush = ISC_FALSE;
223 	view->dlv = NULL;
224 	view->maxudp = 0;
225 	view->staleanswerttl = 1;
226 	view->staleanswersok = dns_stale_answer_conf;
227 	view->staleanswersenable = ISC_FALSE;
228 	view->nocookieudp = 0;
229 	view->padding = 0;
230 	view->pad_acl = NULL;
231 	view->maxbits = 0;
232 	view->v4_aaaa = dns_aaaa_ok;
233 	view->v6_aaaa = dns_aaaa_ok;
234 	view->aaaa_acl = NULL;
235 	view->rpzs = NULL;
236 	view->catzs = NULL;
237 	dns_fixedname_init(&view->dlv_fixed);
238 	view->managed_keys = NULL;
239 	view->redirect = NULL;
240 	view->redirectzone = NULL;
241 	dns_fixedname_init(&view->redirectfixed);
242 	view->requestnsid = ISC_FALSE;
243 	view->sendcookie = ISC_TRUE;
244 	view->requireservercookie = ISC_FALSE;
245 	view->synthfromdnssec = ISC_TRUE;
246 	view->trust_anchor_telemetry = ISC_TRUE;
247 	view->root_key_sentinel = ISC_TRUE;
248 	view->new_zone_dir = NULL;
249 	view->new_zone_file = NULL;
250 	view->new_zone_db = NULL;
251 	view->new_zone_dbenv = NULL;
252 	view->new_zone_mapsize = 0ULL;
253 	view->new_zone_config = NULL;
254 	view->cfg_destroy = NULL;
255 	view->fail_ttl = 0;
256 	view->failcache = NULL;
257 	(void)dns_badcache_init(view->mctx, DNS_VIEW_FAILCACHESIZE,
258 				   &view->failcache);
259 	view->v6bias = 0;
260 	view->dtenv = NULL;
261 	view->dttypes = 0;
262 
263 	result = isc_mutex_init(&view->new_zone_lock);
264 	if (result != ISC_R_SUCCESS)
265 		goto cleanup_dynkeys;
266 
267 	if (isc_bind9) {
268 		result = dns_order_create(view->mctx, &view->order);
269 		if (result != ISC_R_SUCCESS)
270 			goto cleanup_new_zone_lock;
271 	}
272 
273 	result = dns_peerlist_new(view->mctx, &view->peers);
274 	if (result != ISC_R_SUCCESS)
275 		goto cleanup_order;
276 
277 	result = dns_aclenv_init(view->mctx, &view->aclenv);
278 	if (result != ISC_R_SUCCESS)
279 		goto cleanup_peerlist;
280 
281 	ISC_LINK_INIT(view, link);
282 	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
283 		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
284 		       view, NULL, NULL, NULL);
285 	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
286 		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
287 		       view, NULL, NULL, NULL);
288 	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
289 		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
290 		       view, NULL, NULL, NULL);
291 	view->viewlist = NULL;
292 	view->magic = DNS_VIEW_MAGIC;
293 
294 	*viewp = view;
295 
296 	return (ISC_R_SUCCESS);
297 
298  cleanup_peerlist:
299 	if (view->peers != NULL)
300 		dns_peerlist_detach(&view->peers);
301 
302  cleanup_order:
303 	if (view->order != NULL)
304 		dns_order_detach(&view->order);
305 
306  cleanup_new_zone_lock:
307 	DESTROYLOCK(&view->new_zone_lock);
308 
309  cleanup_dynkeys:
310 	if (view->dynamickeys != NULL)
311 		dns_tsigkeyring_detach(&view->dynamickeys);
312 
313  cleanup_references:
314 	isc_refcount_destroy(&view->references);
315 
316  cleanup_fwdtable:
317 	if (view->fwdtable != NULL)
318 		dns_fwdtable_destroy(&view->fwdtable);
319 
320  cleanup_zt:
321 	if (view->zonetable != NULL)
322 		dns_zt_detach(&view->zonetable);
323 
324  cleanup_mutex:
325 	DESTROYLOCK(&view->lock);
326 
327 	if (view->nta_file != NULL)
328 		isc_mem_free(mctx, view->nta_file);
329 
330  cleanup_name:
331 	isc_mem_free(mctx, view->name);
332 
333  cleanup_view:
334 	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
335 
336 	return (result);
337 }
338 
339 static inline void
340 destroy(dns_view_t *view) {
341 	dns_dns64_t *dns64;
342 	dns_dlzdb_t *dlzdb;
343 
344 	REQUIRE(!ISC_LINK_LINKED(view, link));
345 	REQUIRE(isc_refcount_current(&view->references) == 0);
346 	REQUIRE(view->weakrefs == 0);
347 	REQUIRE(RESSHUTDOWN(view));
348 	REQUIRE(ADBSHUTDOWN(view));
349 	REQUIRE(REQSHUTDOWN(view));
350 
351 	if (view->order != NULL)
352 		dns_order_detach(&view->order);
353 	if (view->peers != NULL)
354 		dns_peerlist_detach(&view->peers);
355 
356 	if (view->dynamickeys != NULL) {
357 		isc_result_t result;
358 		char template[PATH_MAX];
359 		char keyfile[PATH_MAX];
360 		FILE *fp = NULL;
361 
362 		result = isc_file_mktemplate(NULL, template, sizeof(template));
363 		if (result == ISC_R_SUCCESS) {
364 			(void)isc_file_openuniqueprivate(template, &fp);
365 		}
366 		if (fp == NULL) {
367 			dns_tsigkeyring_detach(&view->dynamickeys);
368 		} else {
369 			result = dns_tsigkeyring_dumpanddetach
370 				(&view->dynamickeys, fp);
371 			if (result == ISC_R_SUCCESS) {
372 				if (fclose(fp) == 0) {
373 					result = isc_file_sanitize
374 						(NULL, view->name, "tsigkeys",
375 						 keyfile, sizeof(keyfile));
376 					if (result == ISC_R_SUCCESS)
377 						result = isc_file_rename
378 							(template, keyfile);
379 				}
380 				if (result != ISC_R_SUCCESS)
381 					(void)remove(template);
382 			} else {
383 				(void)fclose(fp);
384 				(void)remove(template);
385 			}
386 		}
387 	}
388 	if (view->statickeys != NULL)
389 		dns_tsigkeyring_detach(&view->statickeys);
390 	if (view->adb != NULL)
391 		dns_adb_detach(&view->adb);
392 	if (view->resolver != NULL)
393 		dns_resolver_detach(&view->resolver);
394 	dns_rrl_view_destroy(view);
395 	if (view->rpzs != NULL)
396 		dns_rpz_detach_rpzs(&view->rpzs);
397 	if (view->catzs != NULL)
398 		dns_catz_catzs_detach(&view->catzs);
399 	for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
400 	     dlzdb != NULL;
401 	     dlzdb = ISC_LIST_HEAD(view->dlz_searched)) {
402 		ISC_LIST_UNLINK(view->dlz_searched, dlzdb, link);
403 		dns_dlzdestroy(&dlzdb);
404 	}
405 	for (dlzdb = ISC_LIST_HEAD(view->dlz_unsearched);
406 	     dlzdb != NULL;
407 	     dlzdb = ISC_LIST_HEAD(view->dlz_unsearched)) {
408 		ISC_LIST_UNLINK(view->dlz_unsearched, dlzdb, link);
409 		dns_dlzdestroy(&dlzdb);
410 	}
411 	if (view->requestmgr != NULL)
412 		dns_requestmgr_detach(&view->requestmgr);
413 	if (view->task != NULL)
414 		isc_task_detach(&view->task);
415 	if (view->hints != NULL)
416 		dns_db_detach(&view->hints);
417 	if (view->cachedb != NULL)
418 		dns_db_detach(&view->cachedb);
419 	if (view->cache != NULL)
420 		dns_cache_detach(&view->cache);
421 	if (view->nocasecompress != NULL)
422 		dns_acl_detach(&view->nocasecompress);
423 	if (view->matchclients != NULL)
424 		dns_acl_detach(&view->matchclients);
425 	if (view->matchdestinations != NULL)
426 		dns_acl_detach(&view->matchdestinations);
427 	if (view->cacheacl != NULL)
428 		dns_acl_detach(&view->cacheacl);
429 	if (view->cacheonacl != NULL)
430 		dns_acl_detach(&view->cacheonacl);
431 	if (view->queryacl != NULL)
432 		dns_acl_detach(&view->queryacl);
433 	if (view->queryonacl != NULL)
434 		dns_acl_detach(&view->queryonacl);
435 	if (view->recursionacl != NULL)
436 		dns_acl_detach(&view->recursionacl);
437 	if (view->recursiononacl != NULL)
438 		dns_acl_detach(&view->recursiononacl);
439 	if (view->sortlist != NULL)
440 		dns_acl_detach(&view->sortlist);
441 	if (view->transferacl != NULL)
442 		dns_acl_detach(&view->transferacl);
443 	if (view->notifyacl != NULL)
444 		dns_acl_detach(&view->notifyacl);
445 	if (view->updateacl != NULL)
446 		dns_acl_detach(&view->updateacl);
447 	if (view->upfwdacl != NULL)
448 		dns_acl_detach(&view->upfwdacl);
449 	if (view->denyansweracl != NULL)
450 		dns_acl_detach(&view->denyansweracl);
451 	if (view->aaaa_acl != NULL)
452 		dns_acl_detach(&view->aaaa_acl);
453 	if (view->pad_acl != NULL)
454 		dns_acl_detach(&view->pad_acl);
455 	if (view->answeracl_exclude != NULL)
456 		dns_rbt_destroy(&view->answeracl_exclude);
457 	if (view->denyanswernames != NULL)
458 		dns_rbt_destroy(&view->denyanswernames);
459 	if (view->answernames_exclude != NULL)
460 		dns_rbt_destroy(&view->answernames_exclude);
461 	if (view->delonly != NULL) {
462 		dns_name_t *name;
463 		int i;
464 
465 		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
466 			name = ISC_LIST_HEAD(view->delonly[i]);
467 			while (name != NULL) {
468 				ISC_LIST_UNLINK(view->delonly[i], name, link);
469 				dns_name_free(name, view->mctx);
470 				isc_mem_put(view->mctx, name, sizeof(*name));
471 				name = ISC_LIST_HEAD(view->delonly[i]);
472 			}
473 		}
474 		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
475 			    DNS_VIEW_DELONLYHASH);
476 		view->delonly = NULL;
477 	}
478 	if (view->rootexclude != NULL) {
479 		dns_name_t *name;
480 		int i;
481 
482 		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
483 			name = ISC_LIST_HEAD(view->rootexclude[i]);
484 			while (name != NULL) {
485 				ISC_LIST_UNLINK(view->rootexclude[i],
486 						name, link);
487 				dns_name_free(name, view->mctx);
488 				isc_mem_put(view->mctx, name, sizeof(*name));
489 				name = ISC_LIST_HEAD(view->rootexclude[i]);
490 			}
491 		}
492 		isc_mem_put(view->mctx, view->rootexclude,
493 			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
494 		view->rootexclude = NULL;
495 	}
496 	if (view->adbstats != NULL)
497 		isc_stats_detach(&view->adbstats);
498 	if (view->resstats != NULL)
499 		isc_stats_detach(&view->resstats);
500 	if (view->resquerystats != NULL)
501 		dns_stats_detach(&view->resquerystats);
502 	if (view->secroots_priv != NULL)
503 		dns_keytable_detach(&view->secroots_priv);
504 	if (view->ntatable_priv != NULL)
505 		dns_ntatable_detach(&view->ntatable_priv);
506 	for (dns64 = ISC_LIST_HEAD(view->dns64);
507 	     dns64 != NULL;
508 	     dns64 = ISC_LIST_HEAD(view->dns64)) {
509 		dns_dns64_unlink(&view->dns64, dns64);
510 		dns_dns64_destroy(&dns64);
511 	}
512 	if (view->managed_keys != NULL)
513 		dns_zone_detach(&view->managed_keys);
514 	if (view->redirect != NULL)
515 		dns_zone_detach(&view->redirect);
516 #ifdef HAVE_DNSTAP
517 	if (view->dtenv != NULL)
518 		dns_dt_detach(&view->dtenv);
519 #endif /* HAVE_DNSTAP */
520 	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL, 0ULL);
521 	if (view->new_zone_file != NULL) {
522 		isc_mem_free(view->mctx, view->new_zone_file);
523 		view->new_zone_file = NULL;
524 	}
525 	if (view->new_zone_dir != NULL) {
526 		isc_mem_free(view->mctx, view->new_zone_dir);
527 		view->new_zone_dir = NULL;
528 	}
529 #ifdef HAVE_LMDB
530 	if (view->new_zone_dbenv != NULL) {
531 		mdb_env_close((MDB_env *) view->new_zone_dbenv);
532 		view->new_zone_dbenv = NULL;
533 	}
534 	if (view->new_zone_db != NULL) {
535 		isc_mem_free(view->mctx, view->new_zone_db);
536 		view->new_zone_db = NULL;
537 	}
538 #endif /* HAVE_LMDB */
539 	dns_fwdtable_destroy(&view->fwdtable);
540 	dns_aclenv_destroy(&view->aclenv);
541 	if (view->failcache != NULL)
542 		dns_badcache_destroy(&view->failcache);
543 	DESTROYLOCK(&view->new_zone_lock);
544 	DESTROYLOCK(&view->lock);
545 	isc_refcount_destroy(&view->references);
546 	isc_mem_free(view->mctx, view->nta_file);
547 	isc_mem_free(view->mctx, view->name);
548 	isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
549 }
550 
551 /*
552  * Return true iff 'view' may be freed.
553  * The caller must be holding the view lock.
554  */
555 static isc_boolean_t
556 all_done(dns_view_t *view) {
557 
558 	if (isc_refcount_current(&view->references) == 0 &&
559 	    view->weakrefs == 0 &&
560 	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
561 		return (ISC_TRUE);
562 
563 	return (ISC_FALSE);
564 }
565 
566 void
567 dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
568 
569 	REQUIRE(DNS_VIEW_VALID(source));
570 	REQUIRE(targetp != NULL && *targetp == NULL);
571 
572 	isc_refcount_increment(&source->references, NULL);
573 
574 	*targetp = source;
575 }
576 
577 static void
578 view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
579 	dns_view_t *view;
580 	unsigned int refs;
581 	isc_boolean_t done = ISC_FALSE;
582 
583 	REQUIRE(viewp != NULL);
584 	view = *viewp;
585 	REQUIRE(DNS_VIEW_VALID(view));
586 
587 	if (flush)
588 		view->flush = ISC_TRUE;
589 	isc_refcount_decrement(&view->references, &refs);
590 	if (refs == 0) {
591 		dns_zone_t *mkzone = NULL, *rdzone = NULL;
592 
593 		LOCK(&view->lock);
594 		if (!RESSHUTDOWN(view))
595 			dns_resolver_shutdown(view->resolver);
596 		if (!ADBSHUTDOWN(view))
597 			dns_adb_shutdown(view->adb);
598 		if (!REQSHUTDOWN(view))
599 			dns_requestmgr_shutdown(view->requestmgr);
600 		if (view->zonetable != NULL) {
601 			if (view->flush)
602 				dns_zt_flushanddetach(&view->zonetable);
603 			else
604 				dns_zt_detach(&view->zonetable);
605 		}
606 		if (view->managed_keys != NULL) {
607 			mkzone = view->managed_keys;
608 			view->managed_keys = NULL;
609 			if (view->flush)
610 				dns_zone_flush(mkzone);
611 		}
612 		if (view->redirect != NULL) {
613 			rdzone = view->redirect;
614 			view->redirect = NULL;
615 			if (view->flush)
616 				dns_zone_flush(rdzone);
617 		}
618 		if (view->catzs != NULL) {
619 			dns_catz_catzs_detach(&view->catzs);
620 		}
621 		done = all_done(view);
622 		UNLOCK(&view->lock);
623 
624 		/* Need to detach zones outside view lock */
625 		if (mkzone != NULL)
626 			dns_zone_detach(&mkzone);
627 
628 		if (rdzone != NULL)
629 			dns_zone_detach(&rdzone);
630 	}
631 
632 	*viewp = NULL;
633 
634 	if (done)
635 		destroy(view);
636 }
637 
638 void
639 dns_view_flushanddetach(dns_view_t **viewp) {
640 	view_flushanddetach(viewp, ISC_TRUE);
641 }
642 
643 void
644 dns_view_detach(dns_view_t **viewp) {
645 	view_flushanddetach(viewp, ISC_FALSE);
646 }
647 
648 static isc_result_t
649 dialup(dns_zone_t *zone, void *dummy) {
650 	UNUSED(dummy);
651 	dns_zone_dialup(zone);
652 	return (ISC_R_SUCCESS);
653 }
654 
655 void
656 dns_view_dialup(dns_view_t *view) {
657 	REQUIRE(DNS_VIEW_VALID(view));
658 	REQUIRE(view->zonetable != NULL);
659 
660 	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
661 }
662 
663 void
664 dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
665 
666 	REQUIRE(DNS_VIEW_VALID(source));
667 	REQUIRE(targetp != NULL && *targetp == NULL);
668 
669 	LOCK(&source->lock);
670 	source->weakrefs++;
671 	UNLOCK(&source->lock);
672 
673 	*targetp = source;
674 }
675 
676 void
677 dns_view_weakdetach(dns_view_t **viewp) {
678 	dns_view_t *view;
679 	isc_boolean_t done = ISC_FALSE;
680 
681 	REQUIRE(viewp != NULL);
682 	view = *viewp;
683 	REQUIRE(DNS_VIEW_VALID(view));
684 
685 	LOCK(&view->lock);
686 
687 	INSIST(view->weakrefs > 0);
688 	view->weakrefs--;
689 	done = all_done(view);
690 
691 	UNLOCK(&view->lock);
692 
693 	*viewp = NULL;
694 
695 	if (done)
696 		destroy(view);
697 }
698 
699 static void
700 resolver_shutdown(isc_task_t *task, isc_event_t *event) {
701 	dns_view_t *view = event->ev_arg;
702 	isc_boolean_t done;
703 
704 	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
705 	REQUIRE(DNS_VIEW_VALID(view));
706 	REQUIRE(view->task == task);
707 
708 	UNUSED(task);
709 
710 	isc_event_free(&event);
711 
712 	LOCK(&view->lock);
713 
714 	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
715 	done = all_done(view);
716 
717 	UNLOCK(&view->lock);
718 
719 	if (done)
720 		destroy(view);
721 }
722 
723 static void
724 adb_shutdown(isc_task_t *task, isc_event_t *event) {
725 	dns_view_t *view = event->ev_arg;
726 	isc_boolean_t done;
727 
728 	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
729 	REQUIRE(DNS_VIEW_VALID(view));
730 	REQUIRE(view->task == task);
731 
732 	UNUSED(task);
733 
734 	isc_event_free(&event);
735 
736 	LOCK(&view->lock);
737 
738 	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
739 	done = all_done(view);
740 
741 	UNLOCK(&view->lock);
742 
743 	if (done)
744 		destroy(view);
745 }
746 
747 static void
748 req_shutdown(isc_task_t *task, isc_event_t *event) {
749 	dns_view_t *view = event->ev_arg;
750 	isc_boolean_t done;
751 
752 	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
753 	REQUIRE(DNS_VIEW_VALID(view));
754 	REQUIRE(view->task == task);
755 
756 	UNUSED(task);
757 
758 	isc_event_free(&event);
759 
760 	LOCK(&view->lock);
761 
762 	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
763 	done = all_done(view);
764 
765 	UNLOCK(&view->lock);
766 
767 	if (done)
768 		destroy(view);
769 }
770 
771 isc_result_t
772 dns_view_createzonetable(dns_view_t *view) {
773 
774 	REQUIRE(DNS_VIEW_VALID(view));
775 	REQUIRE(!view->frozen);
776 	REQUIRE(view->zonetable == NULL);
777 
778 	return (dns_zt_create(view->mctx, view->rdclass, &view->zonetable));
779 }
780 
781 isc_result_t
782 dns_view_createresolver(dns_view_t *view,
783 			isc_taskmgr_t *taskmgr,
784 			unsigned int ntasks,
785 			unsigned int ndisp,
786 			isc_socketmgr_t *socketmgr,
787 			isc_timermgr_t *timermgr,
788 			unsigned int options,
789 			dns_dispatchmgr_t *dispatchmgr,
790 			dns_dispatch_t *dispatchv4,
791 			dns_dispatch_t *dispatchv6)
792 {
793 	isc_result_t result;
794 	isc_event_t *event;
795 	isc_mem_t *mctx = NULL;
796 
797 	REQUIRE(DNS_VIEW_VALID(view));
798 	REQUIRE(!view->frozen);
799 	REQUIRE(view->resolver == NULL);
800 
801 	result = isc_task_create(taskmgr, 0, &view->task);
802 	if (result != ISC_R_SUCCESS)
803 		return (result);
804 	isc_task_setname(view->task, "view", view);
805 
806 	result = dns_resolver_create(view, taskmgr, ntasks, ndisp, socketmgr,
807 				     timermgr, options, dispatchmgr,
808 				     dispatchv4, dispatchv6,
809 				     &view->resolver);
810 	if (result != ISC_R_SUCCESS) {
811 		isc_task_detach(&view->task);
812 		return (result);
813 	}
814 	event = &view->resevent;
815 	dns_resolver_whenshutdown(view->resolver, view->task, &event);
816 	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
817 
818 	result = isc_mem_create(0, 0, &mctx);
819 	if (result != ISC_R_SUCCESS) {
820 		dns_resolver_shutdown(view->resolver);
821 		return (result);
822 	}
823 
824 	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
825 	isc_mem_setname(mctx, "ADB", NULL);
826 	isc_mem_detach(&mctx);
827 	if (result != ISC_R_SUCCESS) {
828 		dns_resolver_shutdown(view->resolver);
829 		return (result);
830 	}
831 	event = &view->adbevent;
832 	dns_adb_whenshutdown(view->adb, view->task, &event);
833 	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
834 
835 	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
836 				      dns_resolver_taskmgr(view->resolver),
837 				      dns_resolver_dispatchmgr(view->resolver),
838 				      dispatchv4, dispatchv6,
839 				      &view->requestmgr);
840 	if (result != ISC_R_SUCCESS) {
841 		dns_adb_shutdown(view->adb);
842 		dns_resolver_shutdown(view->resolver);
843 		return (result);
844 	}
845 	event = &view->reqevent;
846 	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
847 	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
848 
849 	return (ISC_R_SUCCESS);
850 }
851 
852 void
853 dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
854 	dns_view_setcache2(view, cache, ISC_FALSE);
855 }
856 
857 void
858 dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
859 	REQUIRE(DNS_VIEW_VALID(view));
860 	REQUIRE(!view->frozen);
861 
862 	view->cacheshared = shared;
863 	if (view->cache != NULL) {
864 		dns_db_detach(&view->cachedb);
865 		dns_cache_detach(&view->cache);
866 	}
867 	dns_cache_attach(cache, &view->cache);
868 	dns_cache_attachdb(cache, &view->cachedb);
869 	INSIST(DNS_DB_VALID(view->cachedb));
870 }
871 
872 isc_boolean_t
873 dns_view_iscacheshared(dns_view_t *view) {
874 	REQUIRE(DNS_VIEW_VALID(view));
875 
876 	return (view->cacheshared);
877 }
878 
879 void
880 dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
881 	REQUIRE(DNS_VIEW_VALID(view));
882 	REQUIRE(!view->frozen);
883 	REQUIRE(view->hints == NULL);
884 	REQUIRE(dns_db_iszone(hints));
885 
886 	dns_db_attach(hints, &view->hints);
887 }
888 
889 void
890 dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
891 	REQUIRE(DNS_VIEW_VALID(view));
892 	REQUIRE(ring != NULL);
893 	if (view->statickeys != NULL)
894 		dns_tsigkeyring_detach(&view->statickeys);
895 	dns_tsigkeyring_attach(ring, &view->statickeys);
896 }
897 
898 void
899 dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
900 	REQUIRE(DNS_VIEW_VALID(view));
901 	REQUIRE(ring != NULL);
902 	if (view->dynamickeys != NULL)
903 		dns_tsigkeyring_detach(&view->dynamickeys);
904 	dns_tsigkeyring_attach(ring, &view->dynamickeys);
905 }
906 
907 void
908 dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
909 	REQUIRE(DNS_VIEW_VALID(view));
910 	REQUIRE(ringp != NULL && *ringp == NULL);
911 	if (view->dynamickeys != NULL)
912 		dns_tsigkeyring_attach(view->dynamickeys, ringp);
913 }
914 
915 void
916 dns_view_restorekeyring(dns_view_t *view) {
917 	FILE *fp;
918 	char keyfile[PATH_MAX];
919 	isc_result_t result;
920 
921 	REQUIRE(DNS_VIEW_VALID(view));
922 
923 	if (view->dynamickeys != NULL) {
924 		result = isc_file_sanitize(NULL, view->name, "tsigkeys",
925 					   keyfile, sizeof(keyfile));
926 		if (result == ISC_R_SUCCESS) {
927 			fp = fopen(keyfile, "r");
928 			if (fp != NULL) {
929 				dns_keyring_restore(view->dynamickeys, fp);
930 				(void)fclose(fp);
931 			}
932 		}
933 	}
934 }
935 
936 void
937 dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
938 	REQUIRE(DNS_VIEW_VALID(view));
939 	view->dstport = dstport;
940 }
941 
942 void
943 dns_view_freeze(dns_view_t *view) {
944 	REQUIRE(DNS_VIEW_VALID(view));
945 	REQUIRE(!view->frozen);
946 
947 	if (view->resolver != NULL) {
948 		INSIST(view->cachedb != NULL);
949 		dns_resolver_freeze(view->resolver);
950 	}
951 	view->frozen = ISC_TRUE;
952 }
953 
954 void
955 dns_view_thaw(dns_view_t *view) {
956 	REQUIRE(DNS_VIEW_VALID(view));
957 	REQUIRE(view->frozen);
958 
959 	view->frozen = ISC_FALSE;
960 }
961 
962 isc_result_t
963 dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
964 	isc_result_t result;
965 
966 	REQUIRE(DNS_VIEW_VALID(view));
967 	REQUIRE(!view->frozen);
968 	REQUIRE(view->zonetable != NULL);
969 
970 	result = dns_zt_mount(view->zonetable, zone);
971 
972 	return (result);
973 }
974 
975 isc_result_t
976 dns_view_findzone(dns_view_t *view, const dns_name_t *name,
977 		  dns_zone_t **zonep)
978 {
979 	isc_result_t result;
980 
981 	REQUIRE(DNS_VIEW_VALID(view));
982 
983 	LOCK(&view->lock);
984 	if (view->zonetable != NULL) {
985 		result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
986 		if (result == DNS_R_PARTIALMATCH) {
987 			dns_zone_detach(zonep);
988 			result = ISC_R_NOTFOUND;
989 		}
990 	} else
991 		result = ISC_R_NOTFOUND;
992 	UNLOCK(&view->lock);
993 
994 	return (result);
995 }
996 
997 isc_result_t
998 dns_view_find(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
999 	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
1000 	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
1001 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
1002 	return (dns_view_find2(view, name, type, now, options, use_hints,
1003 			       ISC_FALSE, dbp, nodep, foundname, rdataset,
1004 			       sigrdataset));
1005 }
1006 
1007 isc_result_t
1008 dns_view_find2(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
1009 	       isc_stdtime_t now, unsigned int options,
1010 	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
1011 	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
1012 	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1013 {
1014 	isc_result_t result;
1015 	dns_db_t *db, *zdb;
1016 	dns_dbnode_t *node, *znode;
1017 	isc_boolean_t is_cache, is_staticstub_zone;
1018 	dns_rdataset_t zrdataset, zsigrdataset;
1019 	dns_zone_t *zone;
1020 
1021 	/*
1022 	 * Find an rdataset whose owner name is 'name', and whose type is
1023 	 * 'type'.
1024 	 */
1025 
1026 	REQUIRE(DNS_VIEW_VALID(view));
1027 	REQUIRE(view->frozen);
1028 	REQUIRE(type != dns_rdatatype_rrsig);
1029 	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
1030 	REQUIRE(nodep == NULL || *nodep == NULL);
1031 
1032 	/*
1033 	 * Initialize.
1034 	 */
1035 	dns_rdataset_init(&zrdataset);
1036 	dns_rdataset_init(&zsigrdataset);
1037 	zdb = NULL;
1038 	znode = NULL;
1039 
1040 	/*
1041 	 * Find a database to answer the query.
1042 	 */
1043 	db = NULL;
1044 	node = NULL;
1045 	is_staticstub_zone = ISC_FALSE;
1046 	zone = NULL;
1047 	LOCK(&view->lock);
1048 	if (view->zonetable != NULL)
1049 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1050 	else
1051 		result = ISC_R_NOTFOUND;
1052 	UNLOCK(&view->lock);
1053 	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
1054 	    !use_static_stub)
1055 		result = ISC_R_NOTFOUND;
1056 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
1057 		result = dns_zone_getdb(zone, &db);
1058 		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
1059 			dns_db_attach(view->cachedb, &db);
1060 		else if (result != ISC_R_SUCCESS)
1061 			goto cleanup;
1062 		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
1063 		    dns_name_equal(name, dns_zone_getorigin(zone))) {
1064 			is_staticstub_zone = ISC_TRUE;
1065 		}
1066 	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
1067 		dns_db_attach(view->cachedb, &db);
1068 	else
1069 		goto cleanup;
1070 
1071 	is_cache = dns_db_iscache(db);
1072 
1073  db_find:
1074 	/*
1075 	 * Now look for an answer in the database.
1076 	 */
1077 	result = dns_db_find(db, name, NULL, type, options,
1078 			     now, &node, foundname, rdataset, sigrdataset);
1079 
1080 	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
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 (node != NULL)
1087 			dns_db_detachnode(db, &node);
1088 		if (!is_cache) {
1089 			dns_db_detach(&db);
1090 			if (view->cachedb != NULL && !is_staticstub_zone) {
1091 				/*
1092 				 * Either the answer is in the cache, or we
1093 				 * don't know it.
1094 				 * Note that if the result comes from a
1095 				 * static-stub zone we stop the search here
1096 				 * (see the function description in view.h).
1097 				 */
1098 				is_cache = ISC_TRUE;
1099 				dns_db_attach(view->cachedb, &db);
1100 				goto db_find;
1101 			}
1102 		} else {
1103 			/*
1104 			 * We don't have the data in the cache.  If we've got
1105 			 * glue from the zone, use it.
1106 			 */
1107 			if (dns_rdataset_isassociated(&zrdataset)) {
1108 				dns_rdataset_clone(&zrdataset, rdataset);
1109 				if (sigrdataset != NULL &&
1110 				    dns_rdataset_isassociated(&zsigrdataset))
1111 					dns_rdataset_clone(&zsigrdataset,
1112 							   sigrdataset);
1113 				result = DNS_R_GLUE;
1114 				if (db != NULL)
1115 					dns_db_detach(&db);
1116 				dns_db_attach(zdb, &db);
1117 				dns_db_attachnode(db, znode, &node);
1118 				goto cleanup;
1119 			}
1120 		}
1121 		/*
1122 		 * We don't know the answer.
1123 		 */
1124 		result = ISC_R_NOTFOUND;
1125 	} else if (result == DNS_R_GLUE) {
1126 		if (view->cachedb != NULL && !is_staticstub_zone) {
1127 			/*
1128 			 * We found an answer, but the cache may be better.
1129 			 * Remember what we've got and go look in the cache.
1130 			 */
1131 			is_cache = ISC_TRUE;
1132 			dns_rdataset_clone(rdataset, &zrdataset);
1133 			dns_rdataset_disassociate(rdataset);
1134 			if (sigrdataset != NULL &&
1135 			    dns_rdataset_isassociated(sigrdataset)) {
1136 				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1137 				dns_rdataset_disassociate(sigrdataset);
1138 			}
1139 			dns_db_attach(db, &zdb);
1140 			dns_db_attachnode(zdb, node, &znode);
1141 			dns_db_detachnode(db, &node);
1142 			dns_db_detach(&db);
1143 			dns_db_attach(view->cachedb, &db);
1144 			goto db_find;
1145 		}
1146 		/*
1147 		 * Otherwise, the glue is the best answer.
1148 		 */
1149 		result = ISC_R_SUCCESS;
1150 	}
1151 
1152 	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1153 		if (dns_rdataset_isassociated(rdataset))
1154 			dns_rdataset_disassociate(rdataset);
1155 		if (sigrdataset != NULL &&
1156 		    dns_rdataset_isassociated(sigrdataset))
1157 			dns_rdataset_disassociate(sigrdataset);
1158 		if (db != NULL) {
1159 			if (node != NULL)
1160 				dns_db_detachnode(db, &node);
1161 			dns_db_detach(&db);
1162 		}
1163 		result = dns_db_find(view->hints, name, NULL, type, options,
1164 				     now, &node, foundname,
1165 				     rdataset, sigrdataset);
1166 		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1167 			/*
1168 			 * We just used a hint.  Let the resolver know it
1169 			 * should consider priming.
1170 			 */
1171 			dns_resolver_prime(view->resolver);
1172 			dns_db_attach(view->hints, &db);
1173 			result = DNS_R_HINT;
1174 		} else if (result == DNS_R_NXRRSET) {
1175 			dns_db_attach(view->hints, &db);
1176 			result = DNS_R_HINTNXRRSET;
1177 		} else if (result == DNS_R_NXDOMAIN)
1178 			result = ISC_R_NOTFOUND;
1179 
1180 		/*
1181 		 * Cleanup if non-standard hints are used.
1182 		 */
1183 		if (db == NULL && node != NULL)
1184 			dns_db_detachnode(view->hints, &node);
1185 	}
1186 
1187  cleanup:
1188 	if (dns_rdataset_isassociated(&zrdataset)) {
1189 		dns_rdataset_disassociate(&zrdataset);
1190 		if (dns_rdataset_isassociated(&zsigrdataset))
1191 			dns_rdataset_disassociate(&zsigrdataset);
1192 	}
1193 
1194 	if (zdb != NULL) {
1195 		if (znode != NULL)
1196 			dns_db_detachnode(zdb, &znode);
1197 		dns_db_detach(&zdb);
1198 	}
1199 
1200 	if (db != NULL) {
1201 		if (node != NULL) {
1202 			if (nodep != NULL)
1203 				*nodep = node;
1204 			else
1205 				dns_db_detachnode(db, &node);
1206 		}
1207 		if (dbp != NULL)
1208 			*dbp = db;
1209 		else
1210 			dns_db_detach(&db);
1211 	} else
1212 		INSIST(node == NULL);
1213 
1214 	if (zone != NULL)
1215 		dns_zone_detach(&zone);
1216 
1217 	return (result);
1218 }
1219 
1220 isc_result_t
1221 dns_view_simplefind(dns_view_t *view, const dns_name_t *name,
1222 		    dns_rdatatype_t type, isc_stdtime_t now,
1223 		    unsigned int options, isc_boolean_t use_hints,
1224 		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1225 {
1226 	isc_result_t result;
1227 	dns_fixedname_t foundname;
1228 
1229 	dns_fixedname_init(&foundname);
1230 	result = dns_view_find(view, name, type, now, options, use_hints,
1231 			       NULL, NULL, dns_fixedname_name(&foundname),
1232 			       rdataset, sigrdataset);
1233 	if (result == DNS_R_NXDOMAIN) {
1234 		/*
1235 		 * The rdataset and sigrdataset of the relevant NSEC record
1236 		 * may be returned, but the caller cannot use them because
1237 		 * foundname is not returned by this simplified API.  We
1238 		 * disassociate them here to prevent any misuse by the caller.
1239 		 */
1240 		if (dns_rdataset_isassociated(rdataset))
1241 			dns_rdataset_disassociate(rdataset);
1242 		if (sigrdataset != NULL &&
1243 		    dns_rdataset_isassociated(sigrdataset))
1244 			dns_rdataset_disassociate(sigrdataset);
1245 	} else if (result != ISC_R_SUCCESS &&
1246 		   result != DNS_R_GLUE &&
1247 		   result != DNS_R_HINT &&
1248 		   result != DNS_R_NCACHENXDOMAIN &&
1249 		   result != DNS_R_NCACHENXRRSET &&
1250 		   result != DNS_R_NXRRSET &&
1251 		   result != DNS_R_HINTNXRRSET &&
1252 		   result != ISC_R_NOTFOUND) {
1253 		if (dns_rdataset_isassociated(rdataset))
1254 			dns_rdataset_disassociate(rdataset);
1255 		if (sigrdataset != NULL &&
1256 		    dns_rdataset_isassociated(sigrdataset))
1257 			dns_rdataset_disassociate(sigrdataset);
1258 		result = ISC_R_NOTFOUND;
1259 	}
1260 
1261 	return (result);
1262 }
1263 
1264 isc_result_t
1265 dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
1266 		     dns_name_t *fname, isc_stdtime_t now, unsigned int options,
1267 		     isc_boolean_t use_hints,
1268 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1269 {
1270 	return(dns_view_findzonecut2(view, name, fname, now, options,
1271 				     use_hints, ISC_TRUE,
1272 				     rdataset, sigrdataset));
1273 }
1274 
1275 isc_result_t
1276 dns_view_findzonecut2(dns_view_t *view, const dns_name_t *name,
1277 		      dns_name_t *fname, isc_stdtime_t now,
1278 		      unsigned int options, isc_boolean_t use_hints,
1279 		      isc_boolean_t use_cache, dns_rdataset_t *rdataset,
1280 		      dns_rdataset_t *sigrdataset)
1281 {
1282 	isc_result_t result;
1283 	dns_db_t *db;
1284 	isc_boolean_t is_cache, use_zone, try_hints;
1285 	dns_zone_t *zone;
1286 	dns_name_t *zfname;
1287 	dns_rdataset_t zrdataset, zsigrdataset;
1288 	dns_fixedname_t zfixedname;
1289 	unsigned int ztoptions = 0;
1290 
1291 	REQUIRE(DNS_VIEW_VALID(view));
1292 	REQUIRE(view->frozen);
1293 
1294 	db = NULL;
1295 	use_zone = ISC_FALSE;
1296 	try_hints = ISC_FALSE;
1297 	zfname = NULL;
1298 
1299 	/*
1300 	 * Initialize.
1301 	 */
1302 	dns_fixedname_init(&zfixedname);
1303 	dns_rdataset_init(&zrdataset);
1304 	dns_rdataset_init(&zsigrdataset);
1305 
1306 	/*
1307 	 * Find the right database.
1308 	 */
1309 	zone = NULL;
1310 	LOCK(&view->lock);
1311 	if (view->zonetable != NULL) {
1312 		if ((options & DNS_DBFIND_NOEXACT) != 0)
1313 			ztoptions |= DNS_ZTFIND_NOEXACT;
1314 		result = dns_zt_find(view->zonetable, name, ztoptions,
1315 				     NULL, &zone);
1316 	} else
1317 		result = ISC_R_NOTFOUND;
1318 	UNLOCK(&view->lock);
1319 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1320 		result = dns_zone_getdb(zone, &db);
1321 	if (result == ISC_R_NOTFOUND) {
1322 		/*
1323 		 * We're not directly authoritative for this query name, nor
1324 		 * is it a subdomain of any zone for which we're
1325 		 * authoritative.
1326 		 */
1327 		if (use_cache && view->cachedb != NULL) {
1328 			/*
1329 			 * We have a cache; try it.
1330 			 */
1331 			dns_db_attach(view->cachedb, &db);
1332 		} else {
1333 			/*
1334 			 * Maybe we have hints...
1335 			 */
1336 			try_hints = ISC_TRUE;
1337 			goto finish;
1338 		}
1339 	} else if (result != ISC_R_SUCCESS) {
1340 		/*
1341 		 * Something is broken.
1342 		 */
1343 		goto cleanup;
1344 	}
1345 	is_cache = dns_db_iscache(db);
1346 
1347  db_find:
1348 	/*
1349 	 * Look for the zonecut.
1350 	 */
1351 	if (!is_cache) {
1352 		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1353 				     now, NULL, fname, rdataset, sigrdataset);
1354 		if (result == DNS_R_DELEGATION)
1355 			result = ISC_R_SUCCESS;
1356 		else if (result != ISC_R_SUCCESS)
1357 			goto cleanup;
1358 		if (use_cache && view->cachedb != NULL && db != view->hints) {
1359 			/*
1360 			 * We found an answer, but the cache may be better.
1361 			 */
1362 			zfname = dns_fixedname_name(&zfixedname);
1363 			result = dns_name_copy(fname, zfname, NULL);
1364 			if (result != ISC_R_SUCCESS)
1365 				goto cleanup;
1366 			dns_rdataset_clone(rdataset, &zrdataset);
1367 			dns_rdataset_disassociate(rdataset);
1368 			if (sigrdataset != NULL &&
1369 			    dns_rdataset_isassociated(sigrdataset)) {
1370 				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1371 				dns_rdataset_disassociate(sigrdataset);
1372 			}
1373 			dns_db_detach(&db);
1374 			dns_db_attach(view->cachedb, &db);
1375 			is_cache = ISC_TRUE;
1376 			goto db_find;
1377 		}
1378 	} else {
1379 		result = dns_db_findzonecut(db, name, options, now, NULL,
1380 					    fname, rdataset, sigrdataset);
1381 		if (result == ISC_R_SUCCESS) {
1382 			if (zfname != NULL &&
1383 			    (!dns_name_issubdomain(fname, zfname) ||
1384 			     (dns_zone_gettype(zone) == dns_zone_staticstub &&
1385 			      dns_name_equal(fname, zfname)))) {
1386 				/*
1387 				 * We found a zonecut in the cache, but our
1388 				 * zone delegation is better.
1389 				 */
1390 				use_zone = ISC_TRUE;
1391 			}
1392 		} else if (result == ISC_R_NOTFOUND) {
1393 			if (zfname != NULL) {
1394 				/*
1395 				 * We didn't find anything in the cache, but we
1396 				 * have a zone delegation, so use it.
1397 				 */
1398 				use_zone = ISC_TRUE;
1399 			} else {
1400 				/*
1401 				 * Maybe we have hints...
1402 				 */
1403 				try_hints = ISC_TRUE;
1404 			}
1405 		} else {
1406 			/*
1407 			 * Something bad happened.
1408 			 */
1409 			goto cleanup;
1410 		}
1411 	}
1412 
1413  finish:
1414 	if (use_zone) {
1415 		if (dns_rdataset_isassociated(rdataset)) {
1416 			dns_rdataset_disassociate(rdataset);
1417 			if (sigrdataset != NULL &&
1418 			    dns_rdataset_isassociated(sigrdataset))
1419 				dns_rdataset_disassociate(sigrdataset);
1420 		}
1421 		result = dns_name_copy(zfname, fname, NULL);
1422 		if (result != ISC_R_SUCCESS)
1423 			goto cleanup;
1424 		dns_rdataset_clone(&zrdataset, rdataset);
1425 		if (sigrdataset != NULL &&
1426 		    dns_rdataset_isassociated(&zrdataset))
1427 			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1428 	} else if (try_hints && use_hints && view->hints != NULL) {
1429 		/*
1430 		 * We've found nothing so far, but we have hints.
1431 		 */
1432 		result = dns_db_find(view->hints, dns_rootname, NULL,
1433 				     dns_rdatatype_ns, 0, now, NULL, fname,
1434 				     rdataset, NULL);
1435 		if (result != ISC_R_SUCCESS) {
1436 			/*
1437 			 * We can't even find the hints for the root
1438 			 * nameservers!
1439 			 */
1440 			if (dns_rdataset_isassociated(rdataset))
1441 				dns_rdataset_disassociate(rdataset);
1442 			result = ISC_R_NOTFOUND;
1443 		}
1444 	}
1445 
1446  cleanup:
1447 	if (dns_rdataset_isassociated(&zrdataset)) {
1448 		dns_rdataset_disassociate(&zrdataset);
1449 		if (dns_rdataset_isassociated(&zsigrdataset))
1450 			dns_rdataset_disassociate(&zsigrdataset);
1451 	}
1452 	if (db != NULL)
1453 		dns_db_detach(&db);
1454 	if (zone != NULL)
1455 		dns_zone_detach(&zone);
1456 
1457 	return (result);
1458 }
1459 
1460 isc_result_t
1461 dns_viewlist_find(dns_viewlist_t *list, const char *name,
1462 		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1463 {
1464 	dns_view_t *view;
1465 
1466 	REQUIRE(list != NULL);
1467 
1468 	for (view = ISC_LIST_HEAD(*list);
1469 	     view != NULL;
1470 	     view = ISC_LIST_NEXT(view, link)) {
1471 		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1472 			break;
1473 	}
1474 	if (view == NULL)
1475 		return (ISC_R_NOTFOUND);
1476 
1477 	dns_view_attach(view, viewp);
1478 
1479 	return (ISC_R_SUCCESS);
1480 }
1481 
1482 isc_result_t
1483 dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name,
1484 		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1485 		      dns_zone_t **zonep)
1486 {
1487 	dns_view_t *view;
1488 	isc_result_t result;
1489 	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1490 	dns_zone_t **zp = NULL;
1491 
1492 	REQUIRE(list != NULL);
1493 	REQUIRE(zonep != NULL && *zonep == NULL);
1494 
1495 	for (view = ISC_LIST_HEAD(*list);
1496 	     view != NULL;
1497 	     view = ISC_LIST_NEXT(view, link)) {
1498 		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1499 			continue;
1500 
1501 		/*
1502 		 * If the zone is defined in more than one view,
1503 		 * treat it as not found.
1504 		 */
1505 		zp = (zone1 == NULL) ? &zone1 : &zone2;
1506 		LOCK(&view->lock);
1507 		if (view->zonetable != NULL)
1508 			result = dns_zt_find(view->zonetable, name, 0,
1509 					     NULL, zp);
1510 		else
1511 			result = ISC_R_NOTFOUND;
1512 		UNLOCK(&view->lock);
1513 		INSIST(result == ISC_R_SUCCESS ||
1514 		       result == ISC_R_NOTFOUND ||
1515 		       result == DNS_R_PARTIALMATCH);
1516 
1517 		/* Treat a partial match as no match */
1518 		if (result == DNS_R_PARTIALMATCH) {
1519 			dns_zone_detach(zp);
1520 			result = ISC_R_NOTFOUND;
1521 			POST(result);
1522 		}
1523 
1524 		if (zone2 != NULL) {
1525 			dns_zone_detach(&zone1);
1526 			dns_zone_detach(&zone2);
1527 			return (ISC_R_MULTIPLE);
1528 		}
1529 	}
1530 
1531 	if (zone1 != NULL) {
1532 		dns_zone_attach(zone1, zonep);
1533 		dns_zone_detach(&zone1);
1534 		return (ISC_R_SUCCESS);
1535 	}
1536 
1537 	return (ISC_R_NOTFOUND);
1538 }
1539 
1540 isc_result_t
1541 dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1542 
1543 	REQUIRE(DNS_VIEW_VALID(view));
1544 	REQUIRE(view->zonetable != NULL);
1545 
1546 	return (dns_zt_load(view->zonetable, stop));
1547 }
1548 
1549 isc_result_t
1550 dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1551 
1552 	REQUIRE(DNS_VIEW_VALID(view));
1553 	REQUIRE(view->zonetable != NULL);
1554 
1555 	return (dns_zt_loadnew(view->zonetable, stop));
1556 }
1557 
1558 isc_result_t
1559 dns_view_asyncload(dns_view_t *view, dns_zt_allloaded_t callback, void *arg) {
1560 	REQUIRE(DNS_VIEW_VALID(view));
1561 	REQUIRE(view->zonetable != NULL);
1562 
1563 	return (dns_zt_asyncload(view->zonetable, callback, arg));
1564 }
1565 
1566 isc_result_t
1567 dns_view_gettsig(dns_view_t *view, const dns_name_t *keyname,
1568 		 dns_tsigkey_t **keyp)
1569 {
1570 	isc_result_t result;
1571 	REQUIRE(keyp != NULL && *keyp == NULL);
1572 
1573 	result = dns_tsigkey_find(keyp, keyname, NULL,
1574 				  view->statickeys);
1575 	if (result == ISC_R_NOTFOUND)
1576 		result = dns_tsigkey_find(keyp, keyname, NULL,
1577 					  view->dynamickeys);
1578 	return (result);
1579 }
1580 
1581 isc_result_t
1582 dns_view_getpeertsig(dns_view_t *view, const isc_netaddr_t *peeraddr,
1583 		     dns_tsigkey_t **keyp)
1584 {
1585 	isc_result_t result;
1586 	dns_name_t *keyname = NULL;
1587 	dns_peer_t *peer = NULL;
1588 
1589 	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1590 	if (result != ISC_R_SUCCESS)
1591 		return (result);
1592 
1593 	result = dns_peer_getkey(peer, &keyname);
1594 	if (result != ISC_R_SUCCESS)
1595 		return (result);
1596 
1597 	result = dns_view_gettsig(view, keyname, keyp);
1598 	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1599 }
1600 
1601 isc_result_t
1602 dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1603 	REQUIRE(DNS_VIEW_VALID(view));
1604 	REQUIRE(source != NULL);
1605 
1606 	return (dns_tsig_verify(source, msg, view->statickeys,
1607 				view->dynamickeys));
1608 }
1609 
1610 isc_result_t
1611 dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1612 	isc_result_t result;
1613 
1614 	REQUIRE(DNS_VIEW_VALID(view));
1615 
1616 	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1617 	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1618 					 &dns_master_style_cache, fp);
1619 	if (result != ISC_R_SUCCESS)
1620 		return (result);
1621 	dns_adb_dump(view->adb, fp);
1622 	dns_resolver_printbadcache(view->resolver, fp);
1623 	dns_badcache_print(view->failcache, "SERVFAIL cache", fp);
1624 	return (ISC_R_SUCCESS);
1625 }
1626 
1627 isc_result_t
1628 dns_view_flushcache(dns_view_t *view) {
1629 	return (dns_view_flushcache2(view, ISC_FALSE));
1630 }
1631 
1632 isc_result_t
1633 dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1634 	isc_result_t result;
1635 
1636 	REQUIRE(DNS_VIEW_VALID(view));
1637 
1638 	if (view->cachedb == NULL)
1639 		return (ISC_R_SUCCESS);
1640 	if (!fixuponly) {
1641 		result = dns_cache_flush(view->cache);
1642 		if (result != ISC_R_SUCCESS)
1643 			return (result);
1644 	}
1645 	dns_db_detach(&view->cachedb);
1646 	dns_cache_attachdb(view->cache, &view->cachedb);
1647 	if (view->resolver != NULL)
1648 		dns_resolver_flushbadcache(view->resolver, NULL);
1649 	if (view->failcache != NULL)
1650 		dns_badcache_flush(view->failcache);
1651 
1652 	dns_adb_flush(view->adb);
1653 	return (ISC_R_SUCCESS);
1654 }
1655 
1656 isc_result_t
1657 dns_view_flushname(dns_view_t *view, const dns_name_t *name) {
1658 	return (dns_view_flushnode(view, name, ISC_FALSE));
1659 }
1660 
1661 isc_result_t
1662 dns_view_flushnode(dns_view_t *view, const dns_name_t *name,
1663 		   isc_boolean_t tree)
1664 {
1665 	isc_result_t result = ISC_R_SUCCESS;
1666 
1667 	REQUIRE(DNS_VIEW_VALID(view));
1668 
1669 	if (tree) {
1670 		if (view->adb != NULL)
1671 			dns_adb_flushnames(view->adb, name);
1672 		if (view->resolver != NULL)
1673 			dns_resolver_flushbadnames(view->resolver, name);
1674 		if (view->failcache != NULL)
1675 			dns_badcache_flushtree(view->failcache, name);
1676 	} else {
1677 		if (view->adb != NULL)
1678 			dns_adb_flushname(view->adb, name);
1679 		if (view->resolver != NULL)
1680 			dns_resolver_flushbadcache(view->resolver, name);
1681 		if (view->failcache != NULL)
1682 			dns_badcache_flushname(view->failcache, name);
1683 	}
1684 
1685 	if (view->cache != NULL)
1686 		result = dns_cache_flushnode(view->cache, name, tree);
1687 
1688 	return (result);
1689 }
1690 
1691 isc_result_t
1692 dns_view_adddelegationonly(dns_view_t *view, const dns_name_t *name) {
1693 	isc_result_t result;
1694 	dns_name_t *item;
1695 	isc_uint32_t hash;
1696 
1697 	REQUIRE(DNS_VIEW_VALID(view));
1698 
1699 	if (view->delonly == NULL) {
1700 		view->delonly = isc_mem_get(view->mctx,
1701 					    sizeof(dns_namelist_t) *
1702 					    DNS_VIEW_DELONLYHASH);
1703 		if (view->delonly == NULL)
1704 			return (ISC_R_NOMEMORY);
1705 		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1706 			ISC_LIST_INIT(view->delonly[hash]);
1707 	}
1708 	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1709 	item = ISC_LIST_HEAD(view->delonly[hash]);
1710 	while (item != NULL && !dns_name_equal(item, name))
1711 		item = ISC_LIST_NEXT(item, link);
1712 	if (item != NULL)
1713 		return (ISC_R_SUCCESS);
1714 	item = isc_mem_get(view->mctx, sizeof(*item));
1715 	if (item == NULL)
1716 		return (ISC_R_NOMEMORY);
1717 	dns_name_init(item, NULL);
1718 	result = dns_name_dup(name, view->mctx, item);
1719 	if (result == ISC_R_SUCCESS)
1720 		ISC_LIST_APPEND(view->delonly[hash], item, link);
1721 	else
1722 		isc_mem_put(view->mctx, item, sizeof(*item));
1723 	return (result);
1724 }
1725 
1726 isc_result_t
1727 dns_view_excludedelegationonly(dns_view_t *view, const dns_name_t *name) {
1728 	isc_result_t result;
1729 	dns_name_t *item;
1730 	isc_uint32_t hash;
1731 
1732 	REQUIRE(DNS_VIEW_VALID(view));
1733 
1734 	if (view->rootexclude == NULL) {
1735 		view->rootexclude = isc_mem_get(view->mctx,
1736 					    sizeof(dns_namelist_t) *
1737 					    DNS_VIEW_DELONLYHASH);
1738 		if (view->rootexclude == NULL)
1739 			return (ISC_R_NOMEMORY);
1740 		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1741 			ISC_LIST_INIT(view->rootexclude[hash]);
1742 	}
1743 	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1744 	item = ISC_LIST_HEAD(view->rootexclude[hash]);
1745 	while (item != NULL && !dns_name_equal(item, name))
1746 		item = ISC_LIST_NEXT(item, link);
1747 	if (item != NULL)
1748 		return (ISC_R_SUCCESS);
1749 	item = isc_mem_get(view->mctx, sizeof(*item));
1750 	if (item == NULL)
1751 		return (ISC_R_NOMEMORY);
1752 	dns_name_init(item, NULL);
1753 	result = dns_name_dup(name, view->mctx, item);
1754 	if (result == ISC_R_SUCCESS)
1755 		ISC_LIST_APPEND(view->rootexclude[hash], item, link);
1756 	else
1757 		isc_mem_put(view->mctx, item, sizeof(*item));
1758 	return (result);
1759 }
1760 
1761 isc_boolean_t
1762 dns_view_isdelegationonly(dns_view_t *view, const dns_name_t *name) {
1763 	dns_name_t *item;
1764 	isc_uint32_t hash;
1765 
1766 	REQUIRE(DNS_VIEW_VALID(view));
1767 
1768 	if (!view->rootdelonly && view->delonly == NULL)
1769 		return (ISC_FALSE);
1770 
1771 	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1772 	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1773 		if (view->rootexclude == NULL)
1774 			return (ISC_TRUE);
1775 		item = ISC_LIST_HEAD(view->rootexclude[hash]);
1776 		while (item != NULL && !dns_name_equal(item, name))
1777 			item = ISC_LIST_NEXT(item, link);
1778 		if (item == NULL)
1779 			return (ISC_TRUE);
1780 	}
1781 
1782 	if (view->delonly == NULL)
1783 		return (ISC_FALSE);
1784 
1785 	item = ISC_LIST_HEAD(view->delonly[hash]);
1786 	while (item != NULL && !dns_name_equal(item, name))
1787 		item = ISC_LIST_NEXT(item, link);
1788 	if (item == NULL)
1789 		return (ISC_FALSE);
1790 	return (ISC_TRUE);
1791 }
1792 
1793 void
1794 dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1795 	REQUIRE(DNS_VIEW_VALID(view));
1796 	view->rootdelonly = value;
1797 }
1798 
1799 isc_boolean_t
1800 dns_view_getrootdelonly(dns_view_t *view) {
1801 	REQUIRE(DNS_VIEW_VALID(view));
1802 	return (view->rootdelonly);
1803 }
1804 
1805 isc_result_t
1806 dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1807 
1808 	REQUIRE(DNS_VIEW_VALID(view));
1809 	REQUIRE(view->zonetable != NULL);
1810 
1811 	return (dns_zt_freezezones(view->zonetable, value));
1812 }
1813 
1814 void
1815 dns_view_setadbstats(dns_view_t *view, isc_stats_t *stats) {
1816 	REQUIRE(DNS_VIEW_VALID(view));
1817 	REQUIRE(!view->frozen);
1818 	REQUIRE(view->adbstats == NULL);
1819 
1820 	isc_stats_attach(stats, &view->adbstats);
1821 }
1822 
1823 void
1824 dns_view_getadbstats(dns_view_t *view, isc_stats_t **statsp) {
1825 	REQUIRE(DNS_VIEW_VALID(view));
1826 	REQUIRE(statsp != NULL && *statsp == NULL);
1827 
1828 	if (view->adbstats != NULL)
1829 		isc_stats_attach(view->adbstats, statsp);
1830 }
1831 
1832 void
1833 dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1834 
1835 	REQUIRE(DNS_VIEW_VALID(view));
1836 	REQUIRE(!view->frozen);
1837 	REQUIRE(view->resstats == NULL);
1838 
1839 	isc_stats_attach(stats, &view->resstats);
1840 }
1841 
1842 void
1843 dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1844 	REQUIRE(DNS_VIEW_VALID(view));
1845 	REQUIRE(statsp != NULL && *statsp == NULL);
1846 
1847 	if (view->resstats != NULL)
1848 		isc_stats_attach(view->resstats, statsp);
1849 }
1850 
1851 void
1852 dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1853 	REQUIRE(DNS_VIEW_VALID(view));
1854 	REQUIRE(!view->frozen);
1855 	REQUIRE(view->resquerystats == NULL);
1856 
1857 	dns_stats_attach(stats, &view->resquerystats);
1858 }
1859 
1860 void
1861 dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1862 	REQUIRE(DNS_VIEW_VALID(view));
1863 	REQUIRE(statsp != NULL && *statsp == NULL);
1864 
1865 	if (view->resquerystats != NULL)
1866 		dns_stats_attach(view->resquerystats, statsp);
1867 }
1868 
1869 isc_result_t
1870 dns_view_initntatable(dns_view_t *view,
1871 		      isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
1872 {
1873 	REQUIRE(DNS_VIEW_VALID(view));
1874 	if (view->ntatable_priv != NULL)
1875 		dns_ntatable_detach(&view->ntatable_priv);
1876 	return (dns_ntatable_create(view, taskmgr, timermgr,
1877 				    &view->ntatable_priv));
1878 }
1879 
1880 isc_result_t
1881 dns_view_getntatable(dns_view_t *view, dns_ntatable_t **ntp) {
1882 	REQUIRE(DNS_VIEW_VALID(view));
1883 	REQUIRE(ntp != NULL && *ntp == NULL);
1884 	if (view->ntatable_priv == NULL)
1885 		return (ISC_R_NOTFOUND);
1886 	dns_ntatable_attach(view->ntatable_priv, ntp);
1887 	return (ISC_R_SUCCESS);
1888 }
1889 
1890 isc_result_t
1891 dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1892 	REQUIRE(DNS_VIEW_VALID(view));
1893 	if (view->secroots_priv != NULL)
1894 		dns_keytable_detach(&view->secroots_priv);
1895 	return (dns_keytable_create(mctx, &view->secroots_priv));
1896 }
1897 
1898 isc_result_t
1899 dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1900 	REQUIRE(DNS_VIEW_VALID(view));
1901 	REQUIRE(ktp != NULL && *ktp == NULL);
1902 	if (view->secroots_priv == NULL)
1903 		return (ISC_R_NOTFOUND);
1904 	dns_keytable_attach(view->secroots_priv, ktp);
1905 	return (ISC_R_SUCCESS);
1906 }
1907 
1908 isc_boolean_t
1909 dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now,
1910 		   const dns_name_t *name, const dns_name_t *anchor)
1911 {
1912 	REQUIRE(DNS_VIEW_VALID(view));
1913 
1914 	if (view->ntatable_priv == NULL)
1915 		return (ISC_FALSE);
1916 
1917 	return (dns_ntatable_covered(view->ntatable_priv, now, name, anchor));
1918 }
1919 
1920 isc_result_t
1921 dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
1922 			isc_stdtime_t now, isc_boolean_t checknta,
1923 			isc_boolean_t *secure_domain)
1924 {
1925 	isc_result_t result;
1926 	isc_boolean_t secure = ISC_FALSE;
1927 	dns_fixedname_t fn;
1928 	dns_name_t *anchor;
1929 
1930 	REQUIRE(DNS_VIEW_VALID(view));
1931 
1932 	if (view->secroots_priv == NULL)
1933 		return (ISC_R_NOTFOUND);
1934 
1935 	anchor = dns_fixedname_initname(&fn);
1936 
1937 	result = dns_keytable_issecuredomain(view->secroots_priv, name,
1938 					     anchor, &secure);
1939 	if (result != ISC_R_SUCCESS)
1940 		return (result);
1941 
1942 	if (checknta && secure && view->ntatable_priv != NULL &&
1943 	    dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
1944 		secure = ISC_FALSE;
1945 
1946 	*secure_domain = secure;
1947 	return (ISC_R_SUCCESS);
1948 }
1949 
1950 void
1951 dns_view_untrust(dns_view_t *view, const dns_name_t *keyname,
1952 		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1953 {
1954 	isc_result_t result;
1955 	unsigned char data[4096];
1956 	dns_rdata_t rdata = DNS_RDATA_INIT;
1957 	isc_buffer_t buffer;
1958 	dst_key_t *key = NULL;
1959 	dns_keytable_t *sr = NULL;
1960 
1961 	/*
1962 	 * Clear the revoke bit, if set, so that the key will match what's
1963 	 * in secroots now.
1964 	 */
1965 	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1966 
1967 	/* Convert dnskey to DST key. */
1968 	isc_buffer_init(&buffer, data, sizeof(data));
1969 	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1970 			     dns_rdatatype_dnskey, dnskey, &buffer);
1971 
1972 	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1973 	if (result != ISC_R_SUCCESS)
1974 		return;
1975 
1976 	result = dns_view_getsecroots(view, &sr);
1977 	if (result == ISC_R_SUCCESS) {
1978 		result = dns_keytable_deletekeynode(sr, key);
1979 
1980 		/*
1981 		 * If key was found in secroots, then it was a
1982 		 * configured trust anchor, and we want to fail
1983 		 * secure. If there are no other configured keys,
1984 		 * then leave a null key so that we can't validate
1985 		 * anymore.
1986 		 */
1987 
1988 		if (result == ISC_R_SUCCESS)
1989 			dns_keytable_marksecure(sr, keyname);
1990 
1991 		dns_keytable_detach(&sr);
1992 	}
1993 
1994 	dst_key_free(&key);
1995 }
1996 
1997 /*
1998  * Create path to a directory and a filename contructed from viewname.
1999  * This is a front-end to isc_file_sanitize(), allowing backward
2000  * compatibility to older versions when a file couldn't be expected
2001  * to be in the specified directory but might be in the current working
2002  * directory instead.
2003  *
2004  * It first tests for the existence of a file <viewname>.<suffix> in
2005  * 'directory'. If the file does not exist, it checks again in the
2006  * current working directory. If it does not exist there either,
2007  * return the path inside the directory.
2008  *
2009  * Returns ISC_R_SUCCESS if a path to an existing file is found or
2010  * a new path is created; returns ISC_R_NOSPACE if the path won't
2011  * fit in 'buflen'.
2012  */
2013 
2014 #ifndef PATH_MAX
2015 #define PATH_MAX 1024
2016 #endif
2017 
2018 static isc_result_t
2019 nz_legacy(const char *directory, const char *viewname,
2020 	  const char *suffix, char *buffer, size_t buflen)
2021 {
2022 	isc_result_t result;
2023 	char newbuf[PATH_MAX];
2024 
2025 	result = isc_file_sanitize(directory, viewname, suffix,
2026 				   buffer, buflen);
2027 	if (result != ISC_R_SUCCESS) {
2028 		return (result);
2029 	} else if (directory == NULL || isc_file_exists(buffer)) {
2030 		return (ISC_R_SUCCESS);
2031 	} else {
2032 		/* Save buffer */
2033 		strlcpy(newbuf, buffer, sizeof(newbuf));
2034 	}
2035 
2036 	/*
2037 	 * It isn't in the specified directory; check CWD.
2038 	 */
2039 	result = isc_file_sanitize(NULL, viewname, suffix, buffer, buflen);
2040 	if (result != ISC_R_SUCCESS || isc_file_exists(buffer)) {
2041 		return (result);
2042 	}
2043 
2044 	/*
2045 	 * File does not exist in either 'directory' or CWD,
2046 	 * so use the path in 'directory'.
2047 	 */
2048 	strlcpy(buffer, newbuf, buflen);
2049 	return (ISC_R_SUCCESS);
2050 }
2051 
2052 isc_result_t
2053 dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
2054 		     void (*cfg_destroy)(void **), isc_uint64_t mapsize)
2055 {
2056 	isc_result_t result = ISC_R_SUCCESS;
2057 	char buffer[1024];
2058 #ifdef HAVE_LMDB
2059 	MDB_env *env = NULL;
2060 	int status;
2061 #endif
2062 
2063 #ifndef HAVE_LMDB
2064 	UNUSED(mapsize);
2065 #endif
2066 
2067 	REQUIRE(DNS_VIEW_VALID(view));
2068 	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
2069 
2070 	if (view->new_zone_file != NULL) {
2071 		isc_mem_free(view->mctx, view->new_zone_file);
2072 		view->new_zone_file = NULL;
2073 	}
2074 
2075 #ifdef HAVE_LMDB
2076 	if (view->new_zone_dbenv != NULL) {
2077 		mdb_env_close((MDB_env *) view->new_zone_dbenv);
2078 		view->new_zone_dbenv = NULL;
2079 	}
2080 
2081 	if (view->new_zone_db != NULL) {
2082 		isc_mem_free(view->mctx, view->new_zone_db);
2083 		view->new_zone_db = NULL;
2084 	}
2085 #endif /* HAVE_LMDB */
2086 
2087 	if (view->new_zone_config != NULL) {
2088 		view->cfg_destroy(&view->new_zone_config);
2089 		view->cfg_destroy = NULL;
2090 	}
2091 
2092 	if (!allow) {
2093 		return (ISC_R_SUCCESS);
2094 	}
2095 
2096 	CHECK(nz_legacy(view->new_zone_dir, view->name, "nzf",
2097 			buffer, sizeof(buffer)));
2098 
2099 	view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
2100 	if (view->new_zone_file == NULL) {
2101 		CHECK(ISC_R_NOMEMORY);
2102 	}
2103 
2104 #ifdef HAVE_LMDB
2105 	CHECK(nz_legacy(view->new_zone_dir, view->name, "nzd",
2106 			buffer, sizeof(buffer)));
2107 
2108 	view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
2109 	if (view->new_zone_db == NULL) {
2110 		CHECK(ISC_R_NOMEMORY);
2111 	}
2112 
2113 	status = mdb_env_create(&env);
2114 	if (status != MDB_SUCCESS) {
2115 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2116 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
2117 			      "mdb_env_create failed: %s",
2118 			      mdb_strerror(status));
2119 		CHECK(ISC_R_FAILURE);
2120 	}
2121 
2122 	if (mapsize != 0ULL) {
2123 		status = mdb_env_set_mapsize(env, mapsize);
2124 		if (status != MDB_SUCCESS) {
2125 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2126 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
2127 				      "mdb_env_set_mapsize failed: %s",
2128 				      mdb_strerror(status));
2129 			CHECK(ISC_R_FAILURE);
2130 		}
2131 		view->new_zone_mapsize = mapsize;
2132 	}
2133 
2134 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
2135 	if (status != MDB_SUCCESS) {
2136 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2137 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
2138 			      "mdb_env_open of '%s' failed: %s",
2139 			      view->new_zone_db, mdb_strerror(status));
2140 		CHECK(ISC_R_FAILURE);
2141 	}
2142 
2143 	view->new_zone_dbenv = env;
2144 	env = NULL;
2145 #endif /* HAVE_LMDB */
2146 
2147 	view->new_zone_config = cfgctx;
2148 	view->cfg_destroy = cfg_destroy;
2149 
2150  cleanup:
2151 	if (result != ISC_R_SUCCESS) {
2152 		if (view->new_zone_file != NULL) {
2153 			isc_mem_free(view->mctx, view->new_zone_file);
2154 			view->new_zone_file = NULL;
2155 		}
2156 
2157 #ifdef HAVE_LMDB
2158 		if (view->new_zone_db != NULL) {
2159 			isc_mem_free(view->mctx, view->new_zone_db);
2160 			view->new_zone_db = NULL;
2161 		}
2162 		if (env != NULL) {
2163 			mdb_env_close(env);
2164 		}
2165 #endif /* HAVE_LMDB */
2166 		view->new_zone_config = NULL;
2167 		view->cfg_destroy = NULL;
2168 	}
2169 
2170 	return (result);
2171 }
2172 
2173 void
2174 dns_view_setnewzonedir(dns_view_t *view, const char *dir) {
2175 	REQUIRE(DNS_VIEW_VALID(view));
2176 
2177 	if (view->new_zone_dir != NULL) {
2178 		isc_mem_free(view->mctx, view->new_zone_dir);
2179 		view->new_zone_dir = NULL;
2180 	}
2181 
2182 	if (dir == NULL) {
2183 		return;
2184 	}
2185 
2186 	view->new_zone_dir = isc_mem_strdup(view->mctx, dir);
2187 }
2188 
2189 const char *
2190 dns_view_getnewzonedir(dns_view_t *view) {
2191 	REQUIRE(DNS_VIEW_VALID(view));
2192 
2193 	return (view->new_zone_dir);
2194 }
2195 
2196 isc_result_t
2197 dns_view_searchdlz(dns_view_t *view, const dns_name_t *name,
2198 		   unsigned int minlabels, dns_clientinfomethods_t *methods,
2199 		   dns_clientinfo_t *clientinfo, dns_db_t **dbp)
2200 {
2201 	dns_fixedname_t fname;
2202 	dns_name_t *zonename;
2203 	unsigned int namelabels;
2204 	unsigned int i;
2205 	isc_result_t result;
2206 	dns_dlzfindzone_t findzone;
2207 	dns_dlzdb_t *dlzdb;
2208 	dns_db_t *db, *best = NULL;
2209 
2210 	/*
2211 	 * Performs checks to make sure data is as we expect it to be.
2212 	 */
2213 	REQUIRE(DNS_VIEW_VALID(view));
2214 	REQUIRE(name != NULL);
2215 	REQUIRE(dbp != NULL && *dbp == NULL);
2216 
2217 	/* setup a "fixed" dns name */
2218 	zonename = dns_fixedname_initname(&fname);
2219 
2220 	/* count the number of labels in the name */
2221 	namelabels = dns_name_countlabels(name);
2222 
2223 	for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
2224 	     dlzdb != NULL;
2225 	     dlzdb = ISC_LIST_NEXT(dlzdb, link))
2226 	{
2227 		REQUIRE(DNS_DLZ_VALID(dlzdb));
2228 
2229 		/*
2230 		 * loop through starting with the longest domain name and
2231 		 * trying shorter names portions of the name until we find a
2232 		 * match, have an error, or are below the 'minlabels'
2233 		 * threshold.  minlabels is 0, if neither the standard
2234 		 * database nor any previous DLZ database had a zone name
2235 		 * match. Otherwise minlabels is the number of labels
2236 		 * in that name.  We need to beat that for a "better"
2237 		 * match for this DLZ database to be authoritative.
2238 		 */
2239 		for (i = namelabels; i > minlabels && i > 1; i--) {
2240 			if (i == namelabels) {
2241 				result = dns_name_copy(name, zonename, NULL);
2242 				if (result != ISC_R_SUCCESS)
2243 					return (result);
2244 			} else
2245 				dns_name_split(name, i, NULL, zonename);
2246 
2247 			/* ask SDLZ driver if the zone is supported */
2248 			db = NULL;
2249 			findzone = dlzdb->implementation->methods->findzone;
2250 			result = (*findzone)(dlzdb->implementation->driverarg,
2251 					     dlzdb->dbdata, dlzdb->mctx,
2252 					     view->rdclass, zonename,
2253 					     methods, clientinfo, &db);
2254 
2255 			if (result != ISC_R_NOTFOUND) {
2256 				if (best != NULL)
2257 					dns_db_detach(&best);
2258 				if (result == ISC_R_SUCCESS) {
2259 					INSIST(db != NULL);
2260 					dns_db_attach(db, &best);
2261 					dns_db_detach(&db);
2262 					minlabels = i;
2263 				} else {
2264 					if (db != NULL)
2265 						dns_db_detach(&db);
2266 					break;
2267 				}
2268 			} else if (db != NULL)
2269 				dns_db_detach(&db);
2270 		}
2271 	}
2272 
2273 	if (best != NULL) {
2274 		dns_db_attach(best, dbp);
2275 		dns_db_detach(&best);
2276 		return (ISC_R_SUCCESS);
2277 	}
2278 
2279 	return (ISC_R_NOTFOUND);
2280 }
2281 
2282 isc_uint32_t
2283 dns_view_getfailttl(dns_view_t *view) {
2284 	REQUIRE(DNS_VIEW_VALID(view));
2285 	return (view->fail_ttl);
2286 }
2287 
2288 void
2289 dns_view_setfailttl(dns_view_t *view, isc_uint32_t fail_ttl) {
2290 	REQUIRE(DNS_VIEW_VALID(view));
2291 	view->fail_ttl = fail_ttl;
2292 }
2293 
2294 isc_result_t
2295 dns_view_saventa(dns_view_t *view) {
2296 	isc_result_t result;
2297 	isc_boolean_t removefile = ISC_FALSE;
2298 	dns_ntatable_t *ntatable = NULL;
2299 	FILE *fp = NULL;
2300 
2301 	REQUIRE(DNS_VIEW_VALID(view));
2302 
2303 	if (view->nta_lifetime == 0)
2304 		return (ISC_R_SUCCESS);
2305 
2306 	/* Open NTA save file for overwrite. */
2307 	CHECK(isc_stdio_open(view->nta_file, "w", &fp));
2308 
2309 	result = dns_view_getntatable(view, &ntatable);
2310 	if (result == ISC_R_NOTFOUND) {
2311 		removefile = ISC_TRUE;
2312 		result = ISC_R_SUCCESS;
2313 		goto cleanup;
2314 	} else
2315 		CHECK(result);
2316 
2317 	result = dns_ntatable_save(ntatable, fp);
2318 	if (result == ISC_R_NOTFOUND) {
2319 		removefile = ISC_TRUE;
2320 		result = ISC_R_SUCCESS;
2321 	} else if (result == ISC_R_SUCCESS) {
2322 		result = isc_stdio_close(fp);
2323 		fp = NULL;
2324 	}
2325 
2326  cleanup:
2327 	if (ntatable != NULL)
2328 		dns_ntatable_detach(&ntatable);
2329 
2330 	if (fp != NULL)
2331 		(void)isc_stdio_close(fp);
2332 
2333 	/* Don't leave half-baked NTA save files lying around. */
2334 	if (result != ISC_R_SUCCESS || removefile)
2335 		(void) isc_file_remove(view->nta_file);
2336 
2337 	return (result);
2338 }
2339 
2340 #define TSTR(t) ((t).value.as_textregion.base)
2341 #define TLEN(t) ((t).value.as_textregion.length)
2342 
2343 isc_result_t
2344 dns_view_loadnta(dns_view_t *view) {
2345 	isc_result_t result;
2346 	dns_ntatable_t *ntatable = NULL;
2347 	isc_lex_t *lex = NULL;
2348 	isc_token_t token;
2349 	isc_stdtime_t now;
2350 
2351 	REQUIRE(DNS_VIEW_VALID(view));
2352 
2353 	if (view->nta_lifetime == 0)
2354 		return (ISC_R_SUCCESS);
2355 
2356 	CHECK(isc_lex_create(view->mctx, 1025, &lex));
2357 	CHECK(isc_lex_openfile(lex, view->nta_file));
2358 	CHECK(dns_view_getntatable(view, &ntatable));
2359 	isc_stdtime_get(&now);
2360 
2361 	for (;;) {
2362 		int options = (ISC_LEXOPT_EOL | ISC_LEXOPT_EOF);
2363 		char *name, *type, *timestamp;
2364 		size_t len;
2365 		dns_fixedname_t fn;
2366 		const dns_name_t *ntaname;
2367 		isc_buffer_t b;
2368 		isc_stdtime_t t;
2369 		isc_boolean_t forced;
2370 
2371 		CHECK(isc_lex_gettoken(lex, options, &token));
2372 		if (token.type == isc_tokentype_eof)
2373 			break;
2374 		else if (token.type != isc_tokentype_string)
2375 			CHECK(ISC_R_UNEXPECTEDTOKEN);
2376 		name = TSTR(token);
2377 		len = TLEN(token);
2378 
2379 		if (strcmp(name, ".") == 0)
2380 			ntaname = dns_rootname;
2381 		else {
2382 			dns_name_t *fname;
2383 			fname = dns_fixedname_initname(&fn);
2384 
2385 			isc_buffer_init(&b, name, (unsigned int)len);
2386 			isc_buffer_add(&b, (unsigned int)len);
2387 			CHECK(dns_name_fromtext(fname, &b, dns_rootname,
2388 						0, NULL));
2389 			ntaname = fname;
2390 		}
2391 
2392 		CHECK(isc_lex_gettoken(lex, options, &token));
2393 		if (token.type != isc_tokentype_string)
2394 			CHECK(ISC_R_UNEXPECTEDTOKEN);
2395 		type = TSTR(token);
2396 
2397 		if (strcmp(type, "regular") == 0)
2398 			forced = ISC_FALSE;
2399 		else if (strcmp(type, "forced") == 0)
2400 			forced = ISC_TRUE;
2401 		else
2402 			CHECK(ISC_R_UNEXPECTEDTOKEN);
2403 
2404 		CHECK(isc_lex_gettoken(lex, options, &token));
2405 		if (token.type != isc_tokentype_string)
2406 			CHECK(ISC_R_UNEXPECTEDTOKEN);
2407 		timestamp = TSTR(token);
2408 		CHECK(dns_time32_fromtext(timestamp, &t));
2409 
2410 		CHECK(isc_lex_gettoken(lex, options, &token));
2411 		if (token.type != isc_tokentype_eol &&
2412 		    token.type != isc_tokentype_eof)
2413 			CHECK(ISC_R_UNEXPECTEDTOKEN);
2414 
2415 		if (now <= t) {
2416 			if (t > (now + 604800))
2417 				t = now + 604800;
2418 
2419 			(void) dns_ntatable_add(ntatable, ntaname,
2420 						forced, 0, t);
2421 		} else {
2422 			char nb[DNS_NAME_FORMATSIZE];
2423 			dns_name_format(ntaname, nb, sizeof(nb));
2424 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2425 				      DNS_LOGMODULE_NTA, ISC_LOG_INFO,
2426 				      "ignoring expired NTA at %s", nb);
2427 		}
2428 	};
2429 
2430  cleanup:
2431 	if (ntatable != NULL)
2432 		dns_ntatable_detach(&ntatable);
2433 
2434 	if (lex != NULL) {
2435 		isc_lex_close(lex);
2436 		isc_lex_destroy(&lex);
2437 	}
2438 
2439 	return (result);
2440 }
2441 
2442 void
2443 dns_view_setviewcommit(dns_view_t *view) {
2444 	REQUIRE(DNS_VIEW_VALID(view));
2445 
2446 	LOCK(&view->lock);
2447 
2448 	if (view->redirect != NULL) {
2449 		dns_zone_setviewcommit(view->redirect);
2450 	}
2451 	if (view->managed_keys != NULL) {
2452 		dns_zone_setviewcommit(view->managed_keys);
2453 	}
2454 	if (view->zonetable != NULL) {
2455 		dns_zt_setviewcommit(view->zonetable);
2456 	}
2457 
2458 	UNLOCK(&view->lock);
2459 }
2460 
2461 void
2462 dns_view_setviewrevert(dns_view_t *view) {
2463 	dns_zt_t *zonetable;
2464 
2465 	REQUIRE(DNS_VIEW_VALID(view));
2466 
2467 	/*
2468 	 * dns_zt_setviewrevert() attempts to lock this view, so we must
2469 	 * release the lock.
2470 	 */
2471 	LOCK(&view->lock);
2472 	if (view->redirect != NULL) {
2473 		dns_zone_setviewrevert(view->redirect);
2474 	}
2475 	if (view->managed_keys != NULL) {
2476 		dns_zone_setviewrevert(view->managed_keys);
2477 	}
2478 	zonetable = view->zonetable;
2479 	UNLOCK(&view->lock);
2480 
2481 	if (zonetable != NULL) {
2482 		dns_zt_setviewrevert(zonetable);
2483 	}
2484 }
2485