xref: /minix/external/bsd/bind/dist/bin/named/server.c (revision bb9622b5)
1 /*	$NetBSD: server.c,v 1.19 2015/07/08 17:28:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*! \file */
21 
22 #include <config.h>
23 
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <limits.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 
31 #include <isc/app.h>
32 #include <isc/base64.h>
33 #include <isc/dir.h>
34 #include <isc/entropy.h>
35 #include <isc/file.h>
36 #include <isc/hash.h>
37 #include <isc/hex.h>
38 #include <isc/httpd.h>
39 #include <isc/lex.h>
40 #include <isc/parseint.h>
41 #include <isc/portset.h>
42 #include <isc/print.h>
43 #include <isc/random.h>
44 #include <isc/refcount.h>
45 #include <isc/resource.h>
46 #include <isc/sha2.h>
47 #include <isc/socket.h>
48 #include <isc/stat.h>
49 #include <isc/stats.h>
50 #include <isc/stdio.h>
51 #include <isc/string.h>
52 #include <isc/task.h>
53 #include <isc/timer.h>
54 #include <isc/util.h>
55 #include <isc/xml.h>
56 
57 #ifdef AES_SIT
58 #include <isc/aes.h>
59 #else
60 #include <isc/hmacsha.h>
61 #endif
62 
63 #include <isccfg/namedconf.h>
64 
65 #include <bind9/check.h>
66 
67 #include <dns/acache.h>
68 #include <dns/adb.h>
69 #include <dns/cache.h>
70 #include <dns/db.h>
71 #include <dns/dispatch.h>
72 #include <dns/dlz.h>
73 #include <dns/dns64.h>
74 #include <dns/forward.h>
75 #include <dns/journal.h>
76 #include <dns/keytable.h>
77 #include <dns/keyvalues.h>
78 #include <dns/lib.h>
79 #include <dns/master.h>
80 #include <dns/masterdump.h>
81 #include <dns/order.h>
82 #include <dns/peer.h>
83 #include <dns/portlist.h>
84 #include <dns/private.h>
85 #include <dns/rbt.h>
86 #include <dns/rdataclass.h>
87 #include <dns/rdatalist.h>
88 #include <dns/rdataset.h>
89 #include <dns/rdatastruct.h>
90 #include <dns/resolver.h>
91 #include <dns/rootns.h>
92 #include <dns/secalg.h>
93 #include <dns/soa.h>
94 #include <dns/stats.h>
95 #include <dns/tkey.h>
96 #include <dns/tsig.h>
97 #include <dns/view.h>
98 #include <dns/zone.h>
99 #include <dns/zt.h>
100 
101 #include <dst/dst.h>
102 #include <dst/result.h>
103 
104 #include <named/client.h>
105 #include <named/config.h>
106 #include <named/control.h>
107 #include <named/geoip.h>
108 #include <named/interfacemgr.h>
109 #include <named/log.h>
110 #include <named/logconf.h>
111 #include <named/lwresd.h>
112 #include <named/main.h>
113 #include <named/os.h>
114 #include <named/server.h>
115 #include <named/statschannel.h>
116 #include <named/tkeyconf.h>
117 #include <named/tsigconf.h>
118 #include <named/zoneconf.h>
119 #ifdef HAVE_LIBSCF
120 #include <named/ns_smf_globals.h>
121 #include <stdlib.h>
122 #endif
123 #ifdef HAVE_GEOIP
124 #include <named/geoip.h>
125 #endif /* HAVE_GEOIP */
126 
127 #ifndef PATH_MAX
128 #define PATH_MAX 1024
129 #endif
130 
131 #ifndef SIZE_MAX
132 #define SIZE_MAX ((size_t)-1)
133 #endif
134 
135 #ifdef TUNE_LARGE
136 #define RESOLVER_NTASKS 523
137 #define UDPBUFFERS 32768
138 #define EXCLBUFFERS 32768
139 #else
140 #define RESOLVER_NTASKS 31
141 #define UDPBUFFERS 1000
142 #define EXCLBUFFERS 4096
143 #endif /* TUNE_LARGE */
144 
145 /*%
146  * Check an operation for failure.  Assumes that the function
147  * using it has a 'result' variable and a 'cleanup' label.
148  */
149 #define CHECK(op) \
150 	do { result = (op);					 \
151 	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
152 	} while (/*CONSTCOND*/0)
153 
154 #define TCHECK(op) \
155 	do { tresult = (op);					 \
156 		if (tresult != ISC_R_SUCCESS) {			 \
157 			isc_buffer_clear(text);			 \
158 			goto cleanup;	 			 \
159 		}						 \
160 	} while (0)
161 
162 #define CHECKM(op, msg) \
163 	do { result = (op);					  \
164 	       if (result != ISC_R_SUCCESS) {			  \
165 			isc_log_write(ns_g_lctx,		  \
166 				      NS_LOGCATEGORY_GENERAL,	  \
167 				      NS_LOGMODULE_SERVER,	  \
168 				      ISC_LOG_ERROR,		  \
169 				      "%s: %s", msg,		  \
170 				      isc_result_totext(result)); \
171 			goto cleanup;				  \
172 		}						  \
173 	} while (/*CONSTCOND*/0)				  \
174 
175 #define CHECKMF(op, msg, file) \
176 	do { result = (op);					  \
177 	       if (result != ISC_R_SUCCESS) {			  \
178 			isc_log_write(ns_g_lctx,		  \
179 				      NS_LOGCATEGORY_GENERAL,	  \
180 				      NS_LOGMODULE_SERVER,	  \
181 				      ISC_LOG_ERROR,		  \
182 				      "%s '%s': %s", msg, file,	  \
183 				      isc_result_totext(result)); \
184 			goto cleanup;				  \
185 		}						  \
186 	} while (/*CONSTCOND*/0)				  \
187 
188 #define CHECKFATAL(op, msg) \
189 	do { result = (op);					  \
190 	       if (result != ISC_R_SUCCESS)			  \
191 			fatal(msg, result);			  \
192 	} while (/*CONSTCOND*/0)				  \
193 
194 /*%
195  * Maximum ADB size for views that share a cache.  Use this limit to suppress
196  * the total of memory footprint, which should be the main reason for sharing
197  * a cache.  Only effective when a finite max-cache-size is specified.
198  * This is currently defined to be 8MB.
199  */
200 #define MAX_ADB_SIZE_FOR_CACHESHARE	8388608U
201 
202 struct ns_dispatch {
203 	isc_sockaddr_t			addr;
204 	unsigned int			dispatchgen;
205 	dns_dispatch_t			*dispatch;
206 	ISC_LINK(struct ns_dispatch)	link;
207 };
208 
209 struct ns_cache {
210 	dns_cache_t			*cache;
211 	dns_view_t			*primaryview;
212 	isc_boolean_t			needflush;
213 	isc_boolean_t			adbsizeadjusted;
214 	ISC_LINK(ns_cache_t)		link;
215 };
216 
217 struct dumpcontext {
218 	isc_mem_t			*mctx;
219 	isc_boolean_t			dumpcache;
220 	isc_boolean_t			dumpzones;
221 	FILE				*fp;
222 	ISC_LIST(struct viewlistentry)	viewlist;
223 	struct viewlistentry		*view;
224 	struct zonelistentry		*zone;
225 	dns_dumpctx_t			*mdctx;
226 	dns_db_t			*db;
227 	dns_db_t			*cache;
228 	isc_task_t			*task;
229 	dns_dbversion_t			*version;
230 };
231 
232 struct viewlistentry {
233 	dns_view_t			*view;
234 	ISC_LINK(struct viewlistentry)	link;
235 	ISC_LIST(struct zonelistentry)	zonelist;
236 };
237 
238 struct zonelistentry {
239 	dns_zone_t			*zone;
240 	ISC_LINK(struct zonelistentry)	link;
241 };
242 
243 /*%
244  * Configuration context to retain for each view that allows
245  * new zones to be added at runtime.
246  */
247 struct cfg_context {
248 	isc_mem_t *			mctx;
249 	cfg_parser_t *			parser;
250 	cfg_obj_t *			config;
251 	cfg_parser_t *			nzparser;
252 	cfg_obj_t *			nzconfig;
253 	cfg_aclconfctx_t *		actx;
254 };
255 
256 /*%
257  * Holds state information for the initial zone loading process.
258  * Uses the isc_refcount structure to count the number of views
259  * with pending zone loads, dereferencing as each view finishes.
260  */
261 typedef struct {
262 		ns_server_t *server;
263 		isc_refcount_t refs;
264 } ns_zoneload_t;
265 
266 /*
267  * These zones should not leak onto the Internet.
268  */
269 const char *empty_zones[] = {
270 	/* RFC 1918 */
271 	"10.IN-ADDR.ARPA",
272 	"16.172.IN-ADDR.ARPA",
273 	"17.172.IN-ADDR.ARPA",
274 	"18.172.IN-ADDR.ARPA",
275 	"19.172.IN-ADDR.ARPA",
276 	"20.172.IN-ADDR.ARPA",
277 	"21.172.IN-ADDR.ARPA",
278 	"22.172.IN-ADDR.ARPA",
279 	"23.172.IN-ADDR.ARPA",
280 	"24.172.IN-ADDR.ARPA",
281 	"25.172.IN-ADDR.ARPA",
282 	"26.172.IN-ADDR.ARPA",
283 	"27.172.IN-ADDR.ARPA",
284 	"28.172.IN-ADDR.ARPA",
285 	"29.172.IN-ADDR.ARPA",
286 	"30.172.IN-ADDR.ARPA",
287 	"31.172.IN-ADDR.ARPA",
288 	"168.192.IN-ADDR.ARPA",
289 
290 	/* RFC 6598 */
291 	"64.100.IN-ADDR.ARPA",
292 	"65.100.IN-ADDR.ARPA",
293 	"66.100.IN-ADDR.ARPA",
294 	"67.100.IN-ADDR.ARPA",
295 	"68.100.IN-ADDR.ARPA",
296 	"69.100.IN-ADDR.ARPA",
297 	"70.100.IN-ADDR.ARPA",
298 	"71.100.IN-ADDR.ARPA",
299 	"72.100.IN-ADDR.ARPA",
300 	"73.100.IN-ADDR.ARPA",
301 	"74.100.IN-ADDR.ARPA",
302 	"75.100.IN-ADDR.ARPA",
303 	"76.100.IN-ADDR.ARPA",
304 	"77.100.IN-ADDR.ARPA",
305 	"78.100.IN-ADDR.ARPA",
306 	"79.100.IN-ADDR.ARPA",
307 	"80.100.IN-ADDR.ARPA",
308 	"81.100.IN-ADDR.ARPA",
309 	"82.100.IN-ADDR.ARPA",
310 	"83.100.IN-ADDR.ARPA",
311 	"84.100.IN-ADDR.ARPA",
312 	"85.100.IN-ADDR.ARPA",
313 	"86.100.IN-ADDR.ARPA",
314 	"87.100.IN-ADDR.ARPA",
315 	"88.100.IN-ADDR.ARPA",
316 	"89.100.IN-ADDR.ARPA",
317 	"90.100.IN-ADDR.ARPA",
318 	"91.100.IN-ADDR.ARPA",
319 	"92.100.IN-ADDR.ARPA",
320 	"93.100.IN-ADDR.ARPA",
321 	"94.100.IN-ADDR.ARPA",
322 	"95.100.IN-ADDR.ARPA",
323 	"96.100.IN-ADDR.ARPA",
324 	"97.100.IN-ADDR.ARPA",
325 	"98.100.IN-ADDR.ARPA",
326 	"99.100.IN-ADDR.ARPA",
327 	"100.100.IN-ADDR.ARPA",
328 	"101.100.IN-ADDR.ARPA",
329 	"102.100.IN-ADDR.ARPA",
330 	"103.100.IN-ADDR.ARPA",
331 	"104.100.IN-ADDR.ARPA",
332 	"105.100.IN-ADDR.ARPA",
333 	"106.100.IN-ADDR.ARPA",
334 	"107.100.IN-ADDR.ARPA",
335 	"108.100.IN-ADDR.ARPA",
336 	"109.100.IN-ADDR.ARPA",
337 	"110.100.IN-ADDR.ARPA",
338 	"111.100.IN-ADDR.ARPA",
339 	"112.100.IN-ADDR.ARPA",
340 	"113.100.IN-ADDR.ARPA",
341 	"114.100.IN-ADDR.ARPA",
342 	"115.100.IN-ADDR.ARPA",
343 	"116.100.IN-ADDR.ARPA",
344 	"117.100.IN-ADDR.ARPA",
345 	"118.100.IN-ADDR.ARPA",
346 	"119.100.IN-ADDR.ARPA",
347 	"120.100.IN-ADDR.ARPA",
348 	"121.100.IN-ADDR.ARPA",
349 	"122.100.IN-ADDR.ARPA",
350 	"123.100.IN-ADDR.ARPA",
351 	"124.100.IN-ADDR.ARPA",
352 	"125.100.IN-ADDR.ARPA",
353 	"126.100.IN-ADDR.ARPA",
354 	"127.100.IN-ADDR.ARPA",
355 
356 	/* RFC 5735 and RFC 5737 */
357 	"0.IN-ADDR.ARPA",	/* THIS NETWORK */
358 	"127.IN-ADDR.ARPA",	/* LOOPBACK */
359 	"254.169.IN-ADDR.ARPA",	/* LINK LOCAL */
360 	"2.0.192.IN-ADDR.ARPA",	/* TEST NET */
361 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
362 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
363 	"255.255.255.255.IN-ADDR.ARPA",	/* BROADCAST */
364 
365 	/* Local IPv6 Unicast Addresses */
366 	"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
367 	"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
368 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
369 	"D.F.IP6.ARPA",
370 	"8.E.F.IP6.ARPA",	/* LINK LOCAL */
371 	"9.E.F.IP6.ARPA",	/* LINK LOCAL */
372 	"A.E.F.IP6.ARPA",	/* LINK LOCAL */
373 	"B.E.F.IP6.ARPA",	/* LINK LOCAL */
374 
375 	/* Example Prefix, RFC 3849. */
376 	"8.B.D.0.1.0.0.2.IP6.ARPA",
377 
378 	NULL
379 };
380 
381 ISC_PLATFORM_NORETURN_PRE static void
382 fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
383 
384 static void
385 ns_server_reload(isc_task_t *task, isc_event_t *event);
386 
387 static isc_result_t
388 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
389 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
390 			isc_uint16_t family, ns_listenelt_t **target);
391 static isc_result_t
392 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
393 			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
394 			 isc_uint16_t family, ns_listenlist_t **target);
395 
396 static isc_result_t
397 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
398 		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
399 
400 static isc_result_t
401 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
402 		     const cfg_obj_t *alternates);
403 
404 static isc_result_t
405 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
406 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
407 	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
408 	       isc_boolean_t added, isc_boolean_t old_rpz_ok);
409 
410 static isc_result_t
411 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
412 
413 static void
414 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
415 
416 static void
417 newzone_cfgctx_destroy(void **cfgp);
418 
419 static isc_result_t
420 putstr(isc_buffer_t *b, const char *str);
421 
422 static isc_result_t
423 putnull(isc_buffer_t *b);
424 
425 isc_result_t
426 add_comment(FILE *fp, const char *viewname);
427 
428 /*%
429  * Configure a single view ACL at '*aclp'.  Get its configuration from
430  * 'vconfig' (for per-view configuration) and maybe from 'config'
431  */
432 static isc_result_t
433 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
434 		   const char *aclname, const char *acltuplename,
435 		   cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
436 {
437 	isc_result_t result;
438 	const cfg_obj_t *maps[3];
439 	const cfg_obj_t *aclobj = NULL;
440 	int i = 0;
441 
442 	if (*aclp != NULL)
443 		dns_acl_detach(aclp);
444 	if (vconfig != NULL)
445 		maps[i++] = cfg_tuple_get(vconfig, "options");
446 	if (config != NULL) {
447 		const cfg_obj_t *options = NULL;
448 		(void)cfg_map_get(config, "options", &options);
449 		if (options != NULL)
450 			maps[i++] = options;
451 	}
452 	maps[i] = NULL;
453 
454 	(void)ns_config_get(maps, aclname, &aclobj);
455 	if (aclobj == NULL)
456 		/*
457 		 * No value available.	*aclp == NULL.
458 		 */
459 		return (ISC_R_SUCCESS);
460 
461 	if (acltuplename != NULL) {
462 		/*
463 		 * If the ACL is given in an optional tuple, retrieve it.
464 		 * The parser should have ensured that a valid object be
465 		 * returned.
466 		 */
467 		aclobj = cfg_tuple_get(aclobj, acltuplename);
468 	}
469 
470 	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
471 				    actx, mctx, 0, aclp);
472 
473 	return (result);
474 }
475 
476 /*%
477  * Configure a sortlist at '*aclp'.  Essentially the same as
478  * configure_view_acl() except it calls cfg_acl_fromconfig with a
479  * nest_level value of 2.
480  */
481 static isc_result_t
482 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
483 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
484 			dns_acl_t **aclp)
485 {
486 	isc_result_t result;
487 	const cfg_obj_t *maps[3];
488 	const cfg_obj_t *aclobj = NULL;
489 	int i = 0;
490 
491 	if (*aclp != NULL)
492 		dns_acl_detach(aclp);
493 	if (vconfig != NULL)
494 		maps[i++] = cfg_tuple_get(vconfig, "options");
495 	if (config != NULL) {
496 		const cfg_obj_t *options = NULL;
497 		(void)cfg_map_get(config, "options", &options);
498 		if (options != NULL)
499 			maps[i++] = options;
500 	}
501 	maps[i] = NULL;
502 
503 	(void)ns_config_get(maps, "sortlist", &aclobj);
504 	if (aclobj == NULL)
505 		return (ISC_R_SUCCESS);
506 
507 	/*
508 	 * Use a nest level of 3 for the "top level" of the sortlist;
509 	 * this means each entry in the top three levels will be stored
510 	 * as lists of separate, nested ACLs, rather than merged together
511 	 * into IP tables as is usually done with ACLs.
512 	 */
513 	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
514 				    actx, mctx, 3, aclp);
515 
516 	return (result);
517 }
518 
519 static isc_result_t
520 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
521 			 const char *confname, const char *conftuplename,
522 			 isc_mem_t *mctx, dns_rbt_t **rbtp)
523 {
524 	isc_result_t result;
525 	const cfg_obj_t *maps[3];
526 	const cfg_obj_t *obj = NULL;
527 	const cfg_listelt_t *element;
528 	int i = 0;
529 	dns_fixedname_t fixed;
530 	dns_name_t *name;
531 	isc_buffer_t b;
532 	const char *str;
533 	const cfg_obj_t *nameobj;
534 
535 	if (*rbtp != NULL)
536 		dns_rbt_destroy(rbtp);
537 	if (vconfig != NULL)
538 		maps[i++] = cfg_tuple_get(vconfig, "options");
539 	if (config != NULL) {
540 		const cfg_obj_t *options = NULL;
541 		(void)cfg_map_get(config, "options", &options);
542 		if (options != NULL)
543 			maps[i++] = options;
544 	}
545 	maps[i] = NULL;
546 
547 	(void)ns_config_get(maps, confname, &obj);
548 	if (obj == NULL)
549 		/*
550 		 * No value available.	*rbtp == NULL.
551 		 */
552 		return (ISC_R_SUCCESS);
553 
554 	if (conftuplename != NULL) {
555 		obj = cfg_tuple_get(obj, conftuplename);
556 		if (cfg_obj_isvoid(obj))
557 			return (ISC_R_SUCCESS);
558 	}
559 
560 	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
561 	if (result != ISC_R_SUCCESS)
562 		return (result);
563 
564 	dns_fixedname_init(&fixed);
565 	name = dns_fixedname_name(&fixed);
566 	for (element = cfg_list_first(obj);
567 	     element != NULL;
568 	     element = cfg_list_next(element)) {
569 		nameobj = cfg_listelt_value(element);
570 		str = cfg_obj_asstring(nameobj);
571 		isc_buffer_constinit(&b, str, strlen(str));
572 		isc_buffer_add(&b, strlen(str));
573 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
574 		/*
575 		 * We don't need the node data, but need to set dummy data to
576 		 * avoid a partial match with an empty node.  For example, if
577 		 * we have foo.example.com and bar.example.com, we'd get a match
578 		 * for baz.example.com, which is not the expected result.
579 		 * We simply use (void *)1 as the dummy data.
580 		 */
581 		result = dns_rbt_addname(*rbtp, name, (void *)1);
582 		if (result != ISC_R_SUCCESS) {
583 			cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
584 				    "failed to add %s for %s: %s",
585 				    str, confname, isc_result_totext(result));
586 			goto cleanup;
587 		}
588 
589 	}
590 
591 	return (result);
592 
593   cleanup:
594 	dns_rbt_destroy(rbtp);
595 	return (result);
596 
597 }
598 
599 static isc_result_t
600 dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
601 		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
602 {
603 	dns_rdataclass_t viewclass;
604 	dns_rdata_dnskey_t keystruct;
605 	isc_uint32_t flags, proto, alg;
606 	const char *keystr, *keynamestr;
607 	unsigned char keydata[4096];
608 	isc_buffer_t keydatabuf;
609 	unsigned char rrdata[4096];
610 	isc_buffer_t rrdatabuf;
611 	isc_region_t r;
612 	dns_fixedname_t fkeyname;
613 	dns_name_t *keyname;
614 	isc_buffer_t namebuf;
615 	isc_result_t result;
616 	dst_key_t *dstkey = NULL;
617 
618 	INSIST(target != NULL && *target == NULL);
619 
620 	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
621 	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
622 	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
623 	keyname = dns_fixedname_name(&fkeyname);
624 	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
625 
626 	if (managed) {
627 		const char *initmethod;
628 		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
629 
630 		if (strcasecmp(initmethod, "initial-key") != 0) {
631 			cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
632 				    "managed key '%s': "
633 				    "invalid initialization method '%s'",
634 				    keynamestr, initmethod);
635 			result = ISC_R_FAILURE;
636 			goto cleanup;
637 		}
638 	}
639 
640 	if (vconfig == NULL)
641 		viewclass = dns_rdataclass_in;
642 	else {
643 		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
644 		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
645 					 &viewclass));
646 	}
647 	keystruct.common.rdclass = viewclass;
648 	keystruct.common.rdtype = dns_rdatatype_dnskey;
649 	/*
650 	 * The key data in keystruct is not dynamically allocated.
651 	 */
652 	keystruct.mctx = NULL;
653 
654 	ISC_LINK_INIT(&keystruct.common, link);
655 
656 	if (flags > 0xffff)
657 		CHECKM(ISC_R_RANGE, "key flags");
658 	if (proto > 0xff)
659 		CHECKM(ISC_R_RANGE, "key protocol");
660 	if (alg > 0xff)
661 		CHECKM(ISC_R_RANGE, "key algorithm");
662 	keystruct.flags = (isc_uint16_t)flags;
663 	keystruct.protocol = (isc_uint8_t)proto;
664 	keystruct.algorithm = (isc_uint8_t)alg;
665 
666 	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
667 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
668 
669 	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
670 	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
671 	isc_buffer_usedregion(&keydatabuf, &r);
672 	keystruct.datalen = r.length;
673 	keystruct.data = r.base;
674 
675 	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
676 	     keystruct.algorithm == DST_ALG_RSAMD5) &&
677 	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
678 		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
679 			    "%s key '%s' has a weak exponent",
680 			    managed ? "managed" : "trusted",
681 			    keynamestr);
682 
683 	CHECK(dns_rdata_fromstruct(NULL,
684 				   keystruct.common.rdclass,
685 				   keystruct.common.rdtype,
686 				   &keystruct, &rrdatabuf));
687 	dns_fixedname_init(&fkeyname);
688 	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
689 	isc_buffer_add(&namebuf, strlen(keynamestr));
690 	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
691 	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
692 			      mctx, &dstkey));
693 
694 	*target = dstkey;
695 	return (ISC_R_SUCCESS);
696 
697  cleanup:
698 	if (result == DST_R_NOCRYPTO) {
699 		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
700 			    "ignoring %s key for '%s': no crypto support",
701 			    managed ? "managed" : "trusted",
702 			    keynamestr);
703 	} else if (result == DST_R_UNSUPPORTEDALG) {
704 		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
705 			    "skipping %s key for '%s': %s",
706 			    managed ? "managed" : "trusted",
707 			    keynamestr, isc_result_totext(result));
708 	} else {
709 		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
710 			    "configuring %s key for '%s': %s",
711 			    managed ? "managed" : "trusted",
712 			    keynamestr, isc_result_totext(result));
713 		result = ISC_R_FAILURE;
714 	}
715 
716 	if (dstkey != NULL)
717 		dst_key_free(&dstkey);
718 
719 	return (result);
720 }
721 
722 static isc_result_t
723 load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
724 	       dns_view_t *view, isc_boolean_t managed,
725 	       dns_name_t *keyname, isc_mem_t *mctx)
726 {
727 	const cfg_listelt_t *elt, *elt2;
728 	const cfg_obj_t *key, *keylist;
729 	dst_key_t *dstkey = NULL;
730 	isc_result_t result;
731 	dns_keytable_t *secroots = NULL;
732 
733 	CHECK(dns_view_getsecroots(view, &secroots));
734 
735 	for (elt = cfg_list_first(keys);
736 	     elt != NULL;
737 	     elt = cfg_list_next(elt)) {
738 		keylist = cfg_listelt_value(elt);
739 
740 		for (elt2 = cfg_list_first(keylist);
741 		     elt2 != NULL;
742 		     elt2 = cfg_list_next(elt2)) {
743 			key = cfg_listelt_value(elt2);
744 			result = dstkey_fromconfig(vconfig, key, managed,
745 						   &dstkey, mctx);
746 			if (result ==  DST_R_UNSUPPORTEDALG) {
747 				result = ISC_R_SUCCESS;
748 				continue;
749 			}
750 			if (result != ISC_R_SUCCESS)
751 				goto cleanup;
752 
753 			/*
754 			 * If keyname was specified, we only add that key.
755 			 */
756 			if (keyname != NULL &&
757 			    !dns_name_equal(keyname, dst_key_name(dstkey)))
758 			{
759 				dst_key_free(&dstkey);
760 				continue;
761 			}
762 
763 			CHECK(dns_keytable_add(secroots, managed, &dstkey));
764 		}
765 	}
766 
767  cleanup:
768 	if (dstkey != NULL)
769 		dst_key_free(&dstkey);
770 	if (secroots != NULL)
771 		dns_keytable_detach(&secroots);
772 	if (result == DST_R_NOCRYPTO)
773 		result = ISC_R_SUCCESS;
774 	return (result);
775 }
776 
777 /*%
778  * Configure DNSSEC keys for a view.
779  *
780  * The per-view configuration values and the server-global defaults are read
781  * from 'vconfig' and 'config'.
782  */
783 static isc_result_t
784 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
785 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
786 			  isc_boolean_t auto_dlv, isc_boolean_t auto_root,
787 			  isc_mem_t *mctx)
788 {
789 	isc_result_t result = ISC_R_SUCCESS;
790 	const cfg_obj_t *view_keys = NULL;
791 	const cfg_obj_t *global_keys = NULL;
792 	const cfg_obj_t *view_managed_keys = NULL;
793 	const cfg_obj_t *global_managed_keys = NULL;
794 	const cfg_obj_t *maps[4];
795 	const cfg_obj_t *voptions = NULL;
796 	const cfg_obj_t *options = NULL;
797 	const cfg_obj_t *obj = NULL;
798 	const char *directory;
799 	int i = 0;
800 
801 	/* We don't need trust anchors for the _bind view */
802 	if (strcmp(view->name, "_bind") == 0 &&
803 	    view->rdclass == dns_rdataclass_chaos) {
804 		return (ISC_R_SUCCESS);
805 	}
806 
807 	if (vconfig != NULL) {
808 		voptions = cfg_tuple_get(vconfig, "options");
809 		if (voptions != NULL) {
810 			(void) cfg_map_get(voptions, "trusted-keys",
811 					   &view_keys);
812 			(void) cfg_map_get(voptions, "managed-keys",
813 					   &view_managed_keys);
814 			maps[i++] = voptions;
815 		}
816 	}
817 
818 	if (config != NULL) {
819 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
820 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
821 		(void)cfg_map_get(config, "options", &options);
822 		if (options != NULL) {
823 			maps[i++] = options;
824 		}
825 	}
826 
827 	maps[i++] = ns_g_defaults;
828 	maps[i] = NULL;
829 
830 	result = dns_view_initsecroots(view, mctx);
831 	if (result != ISC_R_SUCCESS) {
832 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
833 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
834 			      "couldn't create keytable");
835 		return (ISC_R_UNEXPECTED);
836 	}
837 
838 	if (auto_dlv && view->rdclass == dns_rdataclass_in) {
839 		const cfg_obj_t *builtin_keys = NULL;
840 		const cfg_obj_t *builtin_managed_keys = NULL;
841 
842 		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
843 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
844 			      "using built-in DLV key for view %s",
845 			      view->name);
846 
847 		/*
848 		 * If bind.keys exists, it overrides the managed-keys
849 		 * clause hard-coded in ns_g_config.
850 		 */
851 		if (bindkeys != NULL) {
852 			(void)cfg_map_get(bindkeys, "trusted-keys",
853 					  &builtin_keys);
854 			(void)cfg_map_get(bindkeys, "managed-keys",
855 					  &builtin_managed_keys);
856 		} else {
857 			(void)cfg_map_get(ns_g_config, "trusted-keys",
858 					  &builtin_keys);
859 			(void)cfg_map_get(ns_g_config, "managed-keys",
860 					  &builtin_managed_keys);
861 		}
862 
863 		if (builtin_keys != NULL)
864 			CHECK(load_view_keys(builtin_keys, vconfig, view,
865 					     ISC_FALSE, view->dlv, mctx));
866 		if (builtin_managed_keys != NULL)
867 			CHECK(load_view_keys(builtin_managed_keys, vconfig,
868 					     view, ISC_TRUE, view->dlv, mctx));
869 	}
870 
871 	if (auto_root && view->rdclass == dns_rdataclass_in) {
872 		const cfg_obj_t *builtin_keys = NULL;
873 		const cfg_obj_t *builtin_managed_keys = NULL;
874 
875 		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
876 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
877 			      "using built-in root key for view %s",
878 			      view->name);
879 
880 		/*
881 		 * If bind.keys exists, it overrides the managed-keys
882 		 * clause hard-coded in ns_g_config.
883 		 */
884 		if (bindkeys != NULL) {
885 			(void)cfg_map_get(bindkeys, "trusted-keys",
886 					  &builtin_keys);
887 			(void)cfg_map_get(bindkeys, "managed-keys",
888 					  &builtin_managed_keys);
889 		} else {
890 			(void)cfg_map_get(ns_g_config, "trusted-keys",
891 					  &builtin_keys);
892 			(void)cfg_map_get(ns_g_config, "managed-keys",
893 					  &builtin_managed_keys);
894 		}
895 
896 		if (builtin_keys != NULL)
897 			CHECK(load_view_keys(builtin_keys, vconfig, view,
898 					     ISC_FALSE, dns_rootname, mctx));
899 		if (builtin_managed_keys != NULL)
900 			CHECK(load_view_keys(builtin_managed_keys, vconfig,
901 					     view, ISC_TRUE, dns_rootname,
902 					     mctx));
903 	}
904 
905 	CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
906 			     NULL, mctx));
907 	CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
908 			     NULL, mctx));
909 
910 	if (view->rdclass == dns_rdataclass_in) {
911 		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
912 				     NULL, mctx));
913 		CHECK(load_view_keys(global_managed_keys, vconfig, view,
914 				     ISC_TRUE, NULL, mctx));
915 	}
916 
917 	/*
918 	 * Add key zone for managed-keys.
919 	 */
920 	obj = NULL;
921 	(void)ns_config_get(maps, "managed-keys-directory", &obj);
922 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
923 	if (directory != NULL)
924 		result = isc_file_isdirectory(directory);
925 	if (result != ISC_R_SUCCESS) {
926 		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
927 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
928 			      "invalid managed-keys-directory %s: %s",
929 			      directory, isc_result_totext(result));
930 		goto cleanup;
931 
932 	}
933 	CHECK(add_keydata_zone(view, directory, ns_g_mctx));
934 
935   cleanup:
936 	return (result);
937 }
938 
939 static isc_result_t
940 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
941 	const cfg_listelt_t *element;
942 	const cfg_obj_t *obj;
943 	const char *str;
944 	dns_fixedname_t fixed;
945 	dns_name_t *name;
946 	isc_boolean_t value;
947 	isc_result_t result;
948 	isc_buffer_t b;
949 
950 	dns_fixedname_init(&fixed);
951 	name = dns_fixedname_name(&fixed);
952 	for (element = cfg_list_first(mbs);
953 	     element != NULL;
954 	     element = cfg_list_next(element))
955 	{
956 		obj = cfg_listelt_value(element);
957 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
958 		isc_buffer_constinit(&b, str, strlen(str));
959 		isc_buffer_add(&b, strlen(str));
960 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
961 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
962 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
963 	}
964 
965 	result = ISC_R_SUCCESS;
966 
967  cleanup:
968 	return (result);
969 }
970 
971 /*%
972  * Get a dispatch appropriate for the resolver of a given view.
973  */
974 static isc_result_t
975 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
976 			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
977 			      isc_boolean_t is_firstview)
978 {
979 	isc_result_t result = ISC_R_FAILURE;
980 	dns_dispatch_t *disp;
981 	isc_sockaddr_t sa;
982 	unsigned int attrs, attrmask;
983 	const cfg_obj_t *obj = NULL;
984 	unsigned int maxdispatchbuffers = UDPBUFFERS;
985 	isc_dscp_t dscp = -1;
986 
987 	switch (af) {
988 	case AF_INET:
989 		result = ns_config_get(maps, "query-source", &obj);
990 		INSIST(result == ISC_R_SUCCESS);
991 		break;
992 	case AF_INET6:
993 		result = ns_config_get(maps, "query-source-v6", &obj);
994 		INSIST(result == ISC_R_SUCCESS);
995 		break;
996 	default:
997 		INSIST(0);
998 	}
999 
1000 	sa = *(cfg_obj_assockaddr(obj));
1001 	INSIST(isc_sockaddr_pf(&sa) == af);
1002 
1003 	dscp = cfg_obj_getdscp(obj);
1004 	if (dscp != -1 && dscpp != NULL)
1005 		*dscpp = dscp;
1006 
1007 	/*
1008 	 * If we don't support this address family, we're done!
1009 	 */
1010 	switch (af) {
1011 	case AF_INET:
1012 		result = isc_net_probeipv4();
1013 		break;
1014 	case AF_INET6:
1015 		result = isc_net_probeipv6();
1016 		break;
1017 	default:
1018 		INSIST(0);
1019 	}
1020 	if (result != ISC_R_SUCCESS)
1021 		return (ISC_R_SUCCESS);
1022 
1023 	/*
1024 	 * Try to find a dispatcher that we can share.
1025 	 */
1026 	attrs = 0;
1027 	attrs |= DNS_DISPATCHATTR_UDP;
1028 	switch (af) {
1029 	case AF_INET:
1030 		attrs |= DNS_DISPATCHATTR_IPV4;
1031 		break;
1032 	case AF_INET6:
1033 		attrs |= DNS_DISPATCHATTR_IPV6;
1034 		break;
1035 	}
1036 	if (isc_sockaddr_getport(&sa) == 0) {
1037 		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1038 		maxdispatchbuffers = EXCLBUFFERS;
1039 	} else {
1040 		INSIST(obj != NULL);
1041 		if (is_firstview) {
1042 			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
1043 				    "using specific query-source port "
1044 				    "suppresses port randomization and can be "
1045 				    "insecure.");
1046 		}
1047 	}
1048 
1049 	attrmask = 0;
1050 	attrmask |= DNS_DISPATCHATTR_UDP;
1051 	attrmask |= DNS_DISPATCHATTR_TCP;
1052 	attrmask |= DNS_DISPATCHATTR_IPV4;
1053 	attrmask |= DNS_DISPATCHATTR_IPV6;
1054 
1055 	disp = NULL;
1056 	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
1057 				     ns_g_taskmgr, &sa, 4096,
1058 				     maxdispatchbuffers, 32768, 16411, 16433,
1059 				     attrs, attrmask, &disp);
1060 	if (result != ISC_R_SUCCESS) {
1061 		isc_sockaddr_t any;
1062 		char buf[ISC_SOCKADDR_FORMATSIZE];
1063 
1064 		switch (af) {
1065 		case AF_INET:
1066 			isc_sockaddr_any(&any);
1067 			break;
1068 		case AF_INET6:
1069 			isc_sockaddr_any6(&any);
1070 			break;
1071 		}
1072 		if (isc_sockaddr_equal(&sa, &any))
1073 			return (ISC_R_SUCCESS);
1074 		isc_sockaddr_format(&sa, buf, sizeof(buf));
1075 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1076 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1077 			      "could not get query source dispatcher (%s)",
1078 			      buf);
1079 		return (result);
1080 	}
1081 
1082 	*dispatchp = disp;
1083 
1084 	return (ISC_R_SUCCESS);
1085 }
1086 
1087 static isc_result_t
1088 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1089 	dns_rdataclass_t rdclass;
1090 	dns_rdatatype_t rdtype;
1091 	const cfg_obj_t *obj;
1092 	dns_fixedname_t fixed;
1093 	unsigned int mode = 0;
1094 	const char *str;
1095 	isc_buffer_t b;
1096 	isc_result_t result;
1097 	isc_boolean_t addroot;
1098 
1099 	result = ns_config_getclass(cfg_tuple_get(ent, "class"),
1100 				    dns_rdataclass_any, &rdclass);
1101 	if (result != ISC_R_SUCCESS)
1102 		return (result);
1103 
1104 	result = ns_config_gettype(cfg_tuple_get(ent, "type"),
1105 				   dns_rdatatype_any, &rdtype);
1106 	if (result != ISC_R_SUCCESS)
1107 		return (result);
1108 
1109 	obj = cfg_tuple_get(ent, "name");
1110 	if (cfg_obj_isstring(obj))
1111 		str = cfg_obj_asstring(obj);
1112 	else
1113 		str = "*";
1114 	addroot = ISC_TF(strcmp(str, "*") == 0);
1115 	isc_buffer_constinit(&b, str, strlen(str));
1116 	isc_buffer_add(&b, strlen(str));
1117 	dns_fixedname_init(&fixed);
1118 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1119 				   dns_rootname, 0, NULL);
1120 	if (result != ISC_R_SUCCESS)
1121 		return (result);
1122 
1123 	obj = cfg_tuple_get(ent, "ordering");
1124 	INSIST(cfg_obj_isstring(obj));
1125 	str = cfg_obj_asstring(obj);
1126 	if (!strcasecmp(str, "fixed"))
1127 #if DNS_RDATASET_FIXED
1128 		mode = DNS_RDATASETATTR_FIXEDORDER;
1129 #else
1130 		mode = 0;
1131 #endif /* DNS_RDATASET_FIXED */
1132 	else if (!strcasecmp(str, "random"))
1133 		mode = DNS_RDATASETATTR_RANDOMIZE;
1134 	else if (!strcasecmp(str, "cyclic"))
1135 		mode = 0;
1136 	else
1137 		INSIST(0);
1138 
1139 	/*
1140 	 * "*" should match everything including the root (BIND 8 compat).
1141 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1142 	 * explicit entry for "." when the name is "*".
1143 	 */
1144 	if (addroot) {
1145 		result = dns_order_add(order, dns_rootname,
1146 				       rdtype, rdclass, mode);
1147 		if (result != ISC_R_SUCCESS)
1148 			return (result);
1149 	}
1150 
1151 	return (dns_order_add(order, dns_fixedname_name(&fixed),
1152 			      rdtype, rdclass, mode));
1153 }
1154 
1155 static isc_result_t
1156 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1157 	isc_netaddr_t na;
1158 	dns_peer_t *peer;
1159 	const cfg_obj_t *obj;
1160 	const char *str;
1161 	isc_result_t result;
1162 	unsigned int prefixlen;
1163 
1164 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1165 
1166 	peer = NULL;
1167 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1168 	if (result != ISC_R_SUCCESS)
1169 		return (result);
1170 
1171 	obj = NULL;
1172 	(void)cfg_map_get(cpeer, "bogus", &obj);
1173 	if (obj != NULL)
1174 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1175 
1176 	obj = NULL;
1177 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1178 	if (obj != NULL)
1179 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1180 
1181 	obj = NULL;
1182 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1183 	if (obj != NULL)
1184 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1185 
1186 	obj = NULL;
1187 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1188 	if (obj != NULL)
1189 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1190 
1191 #ifdef ISC_PLATFORM_USESIT
1192 	obj = NULL;
1193 	(void)cfg_map_get(cpeer, "request-sit", &obj);
1194 	if (obj != NULL)
1195 		CHECK(dns_peer_setrequestsit(peer, cfg_obj_asboolean(obj)));
1196 #endif
1197 
1198 	obj = NULL;
1199 	(void)cfg_map_get(cpeer, "edns", &obj);
1200 	if (obj != NULL)
1201 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1202 
1203 	obj = NULL;
1204 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1205 	if (obj != NULL) {
1206 		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1207 		if (udpsize < 512)
1208 			udpsize = 512;
1209 		if (udpsize > 4096)
1210 			udpsize = 4096;
1211 		CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
1212 	}
1213 
1214 	obj = NULL;
1215 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1216 	if (obj != NULL) {
1217 		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1218 		if (udpsize < 512)
1219 			udpsize = 512;
1220 		if (udpsize > 4096)
1221 			udpsize = 4096;
1222 		CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
1223 	}
1224 
1225 	obj = NULL;
1226 	(void)cfg_map_get(cpeer, "transfers", &obj);
1227 	if (obj != NULL)
1228 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1229 
1230 	obj = NULL;
1231 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1232 	if (obj != NULL) {
1233 		str = cfg_obj_asstring(obj);
1234 		if (strcasecmp(str, "many-answers") == 0)
1235 			CHECK(dns_peer_settransferformat(peer,
1236 							 dns_many_answers));
1237 		else if (strcasecmp(str, "one-answer") == 0)
1238 			CHECK(dns_peer_settransferformat(peer,
1239 							 dns_one_answer));
1240 		else
1241 			INSIST(0);
1242 	}
1243 
1244 	obj = NULL;
1245 	(void)cfg_map_get(cpeer, "keys", &obj);
1246 	if (obj != NULL) {
1247 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1248 		if (result != ISC_R_SUCCESS)
1249 			goto cleanup;
1250 	}
1251 
1252 	obj = NULL;
1253 	if (na.family == AF_INET)
1254 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1255 	else
1256 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1257 	if (obj != NULL) {
1258 		result = dns_peer_settransfersource(peer,
1259 						    cfg_obj_assockaddr(obj));
1260 		if (result != ISC_R_SUCCESS)
1261 			goto cleanup;
1262 		result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
1263 		if (result != ISC_R_SUCCESS)
1264 			goto cleanup;
1265 		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1266 	}
1267 
1268 	obj = NULL;
1269 	if (na.family == AF_INET)
1270 		(void)cfg_map_get(cpeer, "notify-source", &obj);
1271 	else
1272 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1273 	if (obj != NULL) {
1274 		result = dns_peer_setnotifysource(peer,
1275 						  cfg_obj_assockaddr(obj));
1276 		if (result != ISC_R_SUCCESS)
1277 			goto cleanup;
1278 		result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
1279 		if (result != ISC_R_SUCCESS)
1280 			goto cleanup;
1281 		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1282 	}
1283 
1284 	obj = NULL;
1285 	if (na.family == AF_INET)
1286 		(void)cfg_map_get(cpeer, "query-source", &obj);
1287 	else
1288 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1289 	if (obj != NULL) {
1290 		result = dns_peer_setquerysource(peer,
1291 						 cfg_obj_assockaddr(obj));
1292 		if (result != ISC_R_SUCCESS)
1293 			goto cleanup;
1294 		result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
1295 		if (result != ISC_R_SUCCESS)
1296 			goto cleanup;
1297 		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1298 	}
1299 
1300 	*peerp = peer;
1301 	return (ISC_R_SUCCESS);
1302 
1303  cleanup:
1304 	dns_peer_detach(&peer);
1305 	return (result);
1306 }
1307 
1308 static isc_result_t
1309 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1310 	isc_result_t result;
1311 	const cfg_obj_t *algorithms;
1312 	const cfg_listelt_t *element;
1313 	const char *str;
1314 	dns_fixedname_t fixed;
1315 	dns_name_t *name;
1316 	isc_buffer_t b;
1317 
1318 	dns_fixedname_init(&fixed);
1319 	name = dns_fixedname_name(&fixed);
1320 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1321 	isc_buffer_constinit(&b, str, strlen(str));
1322 	isc_buffer_add(&b, strlen(str));
1323 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1324 
1325 	algorithms = cfg_tuple_get(disabled, "algorithms");
1326 	for (element = cfg_list_first(algorithms);
1327 	     element != NULL;
1328 	     element = cfg_list_next(element))
1329 	{
1330 		isc_textregion_t r;
1331 		dns_secalg_t alg;
1332 
1333 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1334 		r.length = strlen(r.base);
1335 
1336 		result = dns_secalg_fromtext(&alg, &r);
1337 		if (result != ISC_R_SUCCESS) {
1338 			isc_uint8_t ui;
1339 			result = isc_parse_uint8(&ui, r.base, 10);
1340 			alg = ui;
1341 		}
1342 		if (result != ISC_R_SUCCESS) {
1343 			cfg_obj_log(cfg_listelt_value(element),
1344 				    ns_g_lctx, ISC_LOG_ERROR,
1345 				    "invalid algorithm");
1346 			CHECK(result);
1347 		}
1348 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1349 	}
1350  cleanup:
1351 	return (result);
1352 }
1353 
1354 static isc_result_t
1355 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1356 	isc_result_t result;
1357 	const cfg_obj_t *digests;
1358 	const cfg_listelt_t *element;
1359 	const char *str;
1360 	dns_fixedname_t fixed;
1361 	dns_name_t *name;
1362 	isc_buffer_t b;
1363 
1364 	dns_fixedname_init(&fixed);
1365 	name = dns_fixedname_name(&fixed);
1366 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1367 	isc_buffer_constinit(&b, str, strlen(str));
1368 	isc_buffer_add(&b, strlen(str));
1369 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1370 
1371 	digests = cfg_tuple_get(disabled, "digests");
1372 	for (element = cfg_list_first(digests);
1373 	     element != NULL;
1374 	     element = cfg_list_next(element))
1375 	{
1376 		isc_textregion_t r;
1377 		dns_dsdigest_t digest;
1378 
1379 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1380 		r.length = strlen(r.base);
1381 
1382 		/* disable_ds_digests handles numeric values. */
1383 		result = dns_dsdigest_fromtext(&digest, &r);
1384 		if (result != ISC_R_SUCCESS) {
1385 			cfg_obj_log(cfg_listelt_value(element),
1386 				    ns_g_lctx, ISC_LOG_ERROR,
1387 				    "invalid algorithm");
1388 			CHECK(result);
1389 		}
1390 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1391 	}
1392  cleanup:
1393 	return (result);
1394 }
1395 
1396 static isc_boolean_t
1397 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1398 	const cfg_listelt_t *element;
1399 	dns_fixedname_t fixed;
1400 	dns_name_t *name;
1401 	isc_result_t result;
1402 	const cfg_obj_t *value;
1403 	const char *str;
1404 	isc_buffer_t b;
1405 
1406 	dns_fixedname_init(&fixed);
1407 	name = dns_fixedname_name(&fixed);
1408 
1409 	for (element = cfg_list_first(disablelist);
1410 	     element != NULL;
1411 	     element = cfg_list_next(element))
1412 	{
1413 		value = cfg_listelt_value(element);
1414 		str = cfg_obj_asstring(value);
1415 		isc_buffer_constinit(&b, str, strlen(str));
1416 		isc_buffer_add(&b, strlen(str));
1417 		result = dns_name_fromtext(name, &b, dns_rootname,
1418 					   0, NULL);
1419 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1420 		if (dns_name_equal(name, zonename))
1421 			return (ISC_TRUE);
1422 	}
1423 	return (ISC_FALSE);
1424 }
1425 
1426 static isc_result_t
1427 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1428 	     isc_mem_t *mctx)
1429 {
1430 	char **argv = NULL;
1431 	unsigned int i;
1432 	isc_result_t result = ISC_R_SUCCESS;
1433 
1434 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1435 
1436 	/*
1437 	 * Check that all the arguments match.
1438 	 */
1439 	for (i = 0; i < dbtypec; i++)
1440 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0)
1441 			CHECK(ISC_R_FAILURE);
1442 
1443 	/*
1444 	 * Check that there are not extra arguments.
1445 	 */
1446 	if (i == dbtypec && argv[i] != NULL)
1447 		result = ISC_R_FAILURE;
1448 
1449  cleanup:
1450 	isc_mem_free(mctx, argv);
1451 	return (result);
1452 }
1453 
1454 static isc_result_t
1455 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1456 	isc_result_t result;
1457 	isc_stats_t *zoneqrystats;
1458 
1459 	dns_zone_setstatlevel(zone, level);
1460 
1461 	zoneqrystats = NULL;
1462 	if (level == dns_zonestat_full) {
1463 		result = isc_stats_create(mctx, &zoneqrystats,
1464 					  dns_nsstatscounter_max);
1465 		if (result != ISC_R_SUCCESS)
1466 			return (result);
1467 	}
1468 	dns_zone_setrequeststats(zone, zoneqrystats);
1469 	if (zoneqrystats != NULL)
1470 		isc_stats_detach(&zoneqrystats);
1471 
1472 	return (ISC_R_SUCCESS);
1473 }
1474 
1475 static ns_cache_t *
1476 cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
1477 	ns_cache_t *nsc;
1478 
1479 	for (nsc = ISC_LIST_HEAD(*cachelist);
1480 	     nsc != NULL;
1481 	     nsc = ISC_LIST_NEXT(nsc, link)) {
1482 		if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1483 			return (nsc);
1484 	}
1485 
1486 	return (NULL);
1487 }
1488 
1489 static isc_boolean_t
1490 cache_reusable(dns_view_t *originview, dns_view_t *view,
1491 	       isc_boolean_t new_zero_no_soattl)
1492 {
1493 	if (originview->checknames != view->checknames ||
1494 	    dns_resolver_getzeronosoattl(originview->resolver) !=
1495 	    new_zero_no_soattl ||
1496 	    originview->acceptexpired != view->acceptexpired ||
1497 	    originview->enablevalidation != view->enablevalidation ||
1498 	    originview->maxcachettl != view->maxcachettl ||
1499 	    originview->maxncachettl != view->maxncachettl) {
1500 		return (ISC_FALSE);
1501 	}
1502 
1503 	return (ISC_TRUE);
1504 }
1505 
1506 static isc_boolean_t
1507 cache_sharable(dns_view_t *originview, dns_view_t *view,
1508 	       isc_boolean_t new_zero_no_soattl,
1509 	       unsigned int new_cleaning_interval,
1510 	       isc_uint64_t new_max_cache_size)
1511 {
1512 	/*
1513 	 * If the cache cannot even reused for the same view, it cannot be
1514 	 * shared with other views.
1515 	 */
1516 	if (!cache_reusable(originview, view, new_zero_no_soattl))
1517 		return (ISC_FALSE);
1518 
1519 	/*
1520 	 * Check other cache related parameters that must be consistent among
1521 	 * the sharing views.
1522 	 */
1523 	if (dns_cache_getcleaninginterval(originview->cache) !=
1524 	    new_cleaning_interval ||
1525 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
1526 		return (ISC_FALSE);
1527 	}
1528 
1529 	return (ISC_TRUE);
1530 }
1531 
1532 /*
1533  * Callback from DLZ configure when the driver sets up a writeable zone
1534  */
1535 static isc_result_t
1536 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1537 	dns_name_t *origin = dns_zone_getorigin(zone);
1538 	dns_rdataclass_t zclass = view->rdclass;
1539 	isc_result_t result;
1540 
1541 	result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
1542 	if (result != ISC_R_SUCCESS)
1543 		return (result);
1544 	dns_zone_setstats(zone, ns_g_server->zonestats);
1545 
1546 	return (ns_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin));
1547 }
1548 
1549 static isc_result_t
1550 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1551 	      unsigned int prefixlen, const char *server,
1552 	      const char *contact)
1553 {
1554 	char *cp;
1555 	char reverse[48+sizeof("ip6.arpa.")];
1556 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1557 	const char *sep = ": view ";
1558 	const char *viewname = view->name;
1559 	const unsigned char *s6;
1560 	dns_fixedname_t fixed;
1561 	dns_name_t *name;
1562 	dns_zone_t *zone = NULL;
1563 	int dns64_dbtypec = 4;
1564 	isc_buffer_t b;
1565 	isc_result_t result;
1566 
1567 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1568 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1569 
1570 	if (!strcmp(viewname, "_default")) {
1571 		sep = "";
1572 		viewname = "";
1573 	}
1574 
1575 	/*
1576 	 * Construct the reverse name of the zone.
1577 	 */
1578 	cp = reverse;
1579 	s6 = na->type.in6.s6_addr;
1580 	while (prefixlen > 0) {
1581 		prefixlen -= 8;
1582 		sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf,
1583 			(s6[prefixlen/8] >> 4) & 0xf);
1584 		cp += 4;
1585 	}
1586 	strcat(cp, "ip6.arpa.");
1587 
1588 	/*
1589 	 * Create the actual zone.
1590 	 */
1591 	if (server != NULL)
1592 		dns64_dbtype[2] = server;
1593 	if (contact != NULL)
1594 		dns64_dbtype[3] = contact;
1595 	dns_fixedname_init(&fixed);
1596 	name = dns_fixedname_name(&fixed);
1597 	isc_buffer_constinit(&b, reverse, strlen(reverse));
1598 	isc_buffer_add(&b, strlen(reverse));
1599 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1600 	CHECK(dns_zone_create(&zone, mctx));
1601 	CHECK(dns_zone_setorigin(zone, name));
1602 	dns_zone_setview(zone, view);
1603 	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1604 	dns_zone_setclass(zone, view->rdclass);
1605 	dns_zone_settype(zone, dns_zone_master);
1606 	dns_zone_setstats(zone, ns_g_server->zonestats);
1607 	CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
1608 	if (view->queryacl != NULL)
1609 		dns_zone_setqueryacl(zone, view->queryacl);
1610 	if (view->queryonacl != NULL)
1611 		dns_zone_setqueryonacl(zone, view->queryonacl);
1612 	dns_zone_setdialup(zone, dns_dialuptype_no);
1613 	dns_zone_setnotifytype(zone, dns_notifytype_no);
1614 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
1615 	CHECK(setquerystats(zone, mctx, dns_zonestat_none));	/* XXXMPA */
1616 	CHECK(dns_view_addzone(view, zone));
1617 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1618 		      ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep,
1619 		      viewname, reverse);
1620 
1621 cleanup:
1622 	if (zone != NULL)
1623 		dns_zone_detach(&zone);
1624 	return (result);
1625 }
1626 
1627 static isc_result_t
1628 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
1629 		   const char *str, const char *msg)
1630 {
1631 	isc_result_t result;
1632 
1633 	result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
1634 	if (result != ISC_R_SUCCESS)
1635 		cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1636 			    "invalid %s '%s'", msg, str);
1637 	return (result);
1638 }
1639 
1640 static isc_result_t
1641 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
1642 		    const char *str, const dns_name_t *origin)
1643 {
1644 	isc_result_t result;
1645 
1646 	result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
1647 				      view->mctx);
1648 	if (result != ISC_R_SUCCESS)
1649 		cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1650 			    "invalid zone '%s'", str);
1651 	return (result);
1652 }
1653 
1654 static isc_result_t
1655 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
1656 		   isc_boolean_t recursive_only_def, dns_ttl_t ttl_def,
1657 		   const dns_rpz_zone_t *old, isc_boolean_t *old_rpz_okp)
1658 {
1659 	const cfg_obj_t *rpz_obj, *obj;
1660 	const char *str;
1661 	dns_rpz_zone_t *new;
1662 	isc_result_t result;
1663 	dns_rpz_num_t rpz_num;
1664 
1665 	REQUIRE(old != NULL || !*old_rpz_okp);
1666 
1667 	rpz_obj = cfg_listelt_value(element);
1668 
1669 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
1670 		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1671 			    "limit of %d response policy zones exceeded",
1672 			    DNS_RPZ_MAX_ZONES);
1673 		return (ISC_R_FAILURE);
1674 	}
1675 
1676 	new = isc_mem_get(view->rpzs->mctx, sizeof(*new));
1677 	if (new == NULL) {
1678 		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1679 			    "no memory for response policy zones");
1680 		return (ISC_R_NOMEMORY);
1681 	}
1682 
1683 	memset(new, 0, sizeof(*new));
1684 	result = isc_refcount_init(&new->refs, 1);
1685 	if (result != ISC_R_SUCCESS) {
1686 		isc_mem_put(view->rpzs->mctx, new, sizeof(*new));
1687 		return (result);
1688 	}
1689 	dns_name_init(&new->origin, NULL);
1690 	dns_name_init(&new->client_ip, NULL);
1691 	dns_name_init(&new->ip, NULL);
1692 	dns_name_init(&new->nsdname, NULL);
1693 	dns_name_init(&new->nsip, NULL);
1694 	dns_name_init(&new->passthru, NULL);
1695 	dns_name_init(&new->drop, NULL);
1696 	dns_name_init(&new->tcp_only, NULL);
1697 	dns_name_init(&new->cname, NULL);
1698 	new->num = view->rpzs->p.num_zones++;
1699 	view->rpzs->zones[new->num] = new;
1700 
1701 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
1702 	if (cfg_obj_isvoid(obj) ? recursive_only_def : cfg_obj_asboolean(obj)) {
1703 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(new->num);
1704 	} else {
1705 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(new->num);
1706 	}
1707 
1708 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
1709 	if (cfg_obj_isuint32(obj)) {
1710 		new->max_policy_ttl = cfg_obj_asuint32(obj);
1711 	} else {
1712 		new->max_policy_ttl = ttl_def;
1713 	}
1714 	if (*old_rpz_okp && new->max_policy_ttl != old->max_policy_ttl)
1715 		*old_rpz_okp = ISC_FALSE;
1716 
1717 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
1718 	result = configure_rpz_name(view, rpz_obj, &new->origin, str, "zone");
1719 	if (result != ISC_R_SUCCESS)
1720 		return (result);
1721 	if (dns_name_equal(&new->origin, dns_rootname)) {
1722 		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1723 			    "invalid zone name '%s'", str);
1724 		return (DNS_R_EMPTYLABEL);
1725 	}
1726 	for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones-1; ++rpz_num) {
1727 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
1728 				   &new->origin)) {
1729 			cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1730 				    "duplicate '%s'", str);
1731 			result = DNS_R_DUPLICATE;
1732 			return (result);
1733 		}
1734 	}
1735 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &new->origin))
1736 		*old_rpz_okp = ISC_FALSE;
1737 
1738 	result = configure_rpz_name2(view, rpz_obj, &new->client_ip,
1739 				     DNS_RPZ_CLIENT_IP_ZONE, &new->origin);
1740 	if (result != ISC_R_SUCCESS)
1741 		return (result);
1742 
1743 	result = configure_rpz_name2(view, rpz_obj, &new->ip,
1744 				     DNS_RPZ_IP_ZONE, &new->origin);
1745 	if (result != ISC_R_SUCCESS)
1746 		return (result);
1747 
1748 	result = configure_rpz_name2(view, rpz_obj, &new->nsdname,
1749 				     DNS_RPZ_NSDNAME_ZONE, &new->origin);
1750 	if (result != ISC_R_SUCCESS)
1751 		return (result);
1752 
1753 	result = configure_rpz_name2(view, rpz_obj, &new->nsip,
1754 				     DNS_RPZ_NSIP_ZONE, &new->origin);
1755 	if (result != ISC_R_SUCCESS)
1756 		return (result);
1757 
1758 	result = configure_rpz_name(view, rpz_obj, &new->passthru,
1759 				    DNS_RPZ_PASSTHRU_NAME, "name");
1760 	if (result != ISC_R_SUCCESS)
1761 		return (result);
1762 
1763 	result = configure_rpz_name(view, rpz_obj, &new->drop,
1764 				    DNS_RPZ_DROP_NAME, "name");
1765 	if (result != ISC_R_SUCCESS)
1766 		return (result);
1767 
1768 	result = configure_rpz_name(view, rpz_obj, &new->tcp_only,
1769 				    DNS_RPZ_TCP_ONLY_NAME, "name");
1770 	if (result != ISC_R_SUCCESS)
1771 		return (result);
1772 
1773 	obj = cfg_tuple_get(rpz_obj, "policy");
1774 	if (cfg_obj_isvoid(obj)) {
1775 		new->policy = DNS_RPZ_POLICY_GIVEN;
1776 	} else {
1777 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
1778 		new->policy = dns_rpz_str2policy(str);
1779 		INSIST(new->policy != DNS_RPZ_POLICY_ERROR);
1780 		if (new->policy == DNS_RPZ_POLICY_CNAME) {
1781 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
1782 			result = configure_rpz_name(view, rpz_obj, &new->cname,
1783 						    str, "cname");
1784 			if (result != ISC_R_SUCCESS)
1785 				return (result);
1786 		}
1787 	}
1788 	if (*old_rpz_okp && (new->policy != old->policy ||
1789 			     !dns_name_equal(&old->cname, &new->cname)))
1790 		*old_rpz_okp = ISC_FALSE;
1791 
1792 	return (ISC_R_SUCCESS);
1793 }
1794 
1795 static isc_result_t
1796 configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
1797 	      isc_boolean_t *old_rpz_okp)
1798 {
1799 	const cfg_listelt_t *zone_element;
1800 	const cfg_obj_t *sub_obj;
1801 	isc_boolean_t recursive_only_def;
1802 	dns_ttl_t ttl_def;
1803 	dns_rpz_zones_t *new;
1804 	const dns_rpz_zones_t *old;
1805 	dns_view_t *pview;
1806 	const dns_rpz_zone_t *old_zone;
1807 	isc_result_t result;
1808 	int i;
1809 
1810 	*old_rpz_okp = ISC_FALSE;
1811 
1812 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
1813 	if (zone_element == NULL)
1814 		return (ISC_R_SUCCESS);
1815 
1816 	result = dns_rpz_new_zones(&view->rpzs, view->mctx);
1817 	if (result != ISC_R_SUCCESS)
1818 		return (result);
1819 	new = view->rpzs;
1820 
1821 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
1822 	if (!cfg_obj_isvoid(sub_obj) &&
1823 	    !cfg_obj_asboolean(sub_obj))
1824 		recursive_only_def = ISC_FALSE;
1825 	else
1826 		recursive_only_def = ISC_TRUE;
1827 
1828 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
1829 	if (!cfg_obj_isvoid(sub_obj) &&
1830 	    cfg_obj_asboolean(sub_obj))
1831 		new->p.break_dnssec = ISC_TRUE;
1832 	else
1833 		new->p.break_dnssec = ISC_FALSE;
1834 
1835 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
1836 	if (cfg_obj_isuint32(sub_obj))
1837 		ttl_def = cfg_obj_asuint32(sub_obj);
1838 	else
1839 		ttl_def = DNS_RPZ_MAX_TTL_DEFAULT;
1840 
1841 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
1842 	if (cfg_obj_isuint32(sub_obj))
1843 		new->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
1844 	else
1845 		new->p.min_ns_labels = 2;
1846 
1847 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
1848 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj))
1849 		new->p.qname_wait_recurse = ISC_TRUE;
1850 	else
1851 		new->p.qname_wait_recurse = ISC_FALSE;
1852 
1853 	pview = NULL;
1854 	result = dns_viewlist_find(&ns_g_server->viewlist,
1855 				   view->name, view->rdclass, &pview);
1856 	if (result == ISC_R_SUCCESS) {
1857 		old = pview->rpzs;
1858 	} else {
1859 		old = NULL;
1860 	}
1861 	if (old == NULL)
1862 		*old_rpz_okp = ISC_FALSE;
1863 	else
1864 		*old_rpz_okp = ISC_TRUE;
1865 
1866 	for (i = 0;
1867 	     zone_element != NULL;
1868 	     ++i, zone_element = cfg_list_next(zone_element)) {
1869 		INSIST(old != NULL || !*old_rpz_okp);
1870 		if (*old_rpz_okp && i < old->p.num_zones) {
1871 			old_zone = old->zones[i];
1872 		} else {
1873 			*old_rpz_okp = ISC_FALSE;
1874 			old_zone = NULL;
1875 		}
1876 		result = configure_rpz_zone(view, zone_element,
1877 					    recursive_only_def, ttl_def,
1878 					    old_zone, old_rpz_okp);
1879 		if (result != ISC_R_SUCCESS) {
1880 			if (pview != NULL)
1881 				dns_view_detach(&pview);
1882 			return (result);
1883 		}
1884 	}
1885 
1886 	/*
1887 	 * If this is a reloading and the parameters and list of policy
1888 	 * zones are unchanged, then use the same policy data.
1889 	 * Data for individual zones that must be reloaded will be merged.
1890 	 */
1891 	if (old != NULL && memcmp(&old->p, &new->p, sizeof(new->p)) != 0)
1892 		*old_rpz_okp = ISC_FALSE;
1893 	if (*old_rpz_okp) {
1894 		dns_rpz_detach_rpzs(&view->rpzs);
1895 		dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
1896 	} else if (old != NULL && pview != NULL) {
1897 		pview->rpzs->rpz_ver += 1;
1898 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
1899 		cfg_obj_log(rpz_obj, ns_g_lctx, ISC_LOG_DEBUG(1),
1900 			    "updated RPZ policy: version %d",
1901 			    view->rpzs->rpz_ver);
1902 	}
1903 	if (pview != NULL)
1904 		dns_view_detach(&pview);
1905 
1906 	return (ISC_R_SUCCESS);
1907 }
1908 
1909 #define CHECK_RRL(cond, pat, val1, val2)				\
1910 	do {								\
1911 		if (!(cond)) {						\
1912 			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,	\
1913 				    pat, val1, val2);			\
1914 			result = ISC_R_RANGE;				\
1915 			goto cleanup;					\
1916 		    }							\
1917 	} while (/*CONSTCOND*/0)
1918 
1919 #define CHECK_RRL_RATE(rate, def, max_rate, name)			\
1920 	do {								\
1921 		obj = NULL;						\
1922 		rrl->rate.str = name;					\
1923 		result = cfg_map_get(map, name, &obj);			\
1924 		if (result == ISC_R_SUCCESS) {				\
1925 			rrl->rate.r = cfg_obj_asuint32(obj);		\
1926 			CHECK_RRL(rrl->rate.r <= max_rate,		\
1927 				  name" %d > %d",			\
1928 				  rrl->rate.r, max_rate);		\
1929 		} else {						\
1930 			rrl->rate.r = def;				\
1931 		}							\
1932 		rrl->rate.scaled = rrl->rate.r;				\
1933 	} while (/*CONSTCOND*/0)
1934 
1935 static isc_result_t
1936 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
1937 	const cfg_obj_t *obj;
1938 	dns_rrl_t *rrl;
1939 	isc_result_t result;
1940 	int min_entries, i, j;
1941 
1942 	/*
1943 	 * Most DNS servers have few clients, but intentinally open
1944 	 * recursive and authoritative servers often have many.
1945 	 * So start with a small number of entries unless told otherwise
1946 	 * to reduce cold-start costs.
1947 	 */
1948 	min_entries = 500;
1949 	obj = NULL;
1950 	result = cfg_map_get(map, "min-table-size", &obj);
1951 	if (result == ISC_R_SUCCESS) {
1952 		min_entries = cfg_obj_asuint32(obj);
1953 		if (min_entries < 1)
1954 			min_entries = 1;
1955 	}
1956 	result = dns_rrl_init(&rrl, view, min_entries);
1957 	if (result != ISC_R_SUCCESS)
1958 		return (result);
1959 
1960 	i = ISC_MAX(20000, min_entries);
1961 	obj = NULL;
1962 	result = cfg_map_get(map, "max-table-size", &obj);
1963 	if (result == ISC_R_SUCCESS) {
1964 		i = cfg_obj_asuint32(obj);
1965 		CHECK_RRL(i >= min_entries,
1966 			  "max-table-size %d < min-table-size %d",
1967 			  i, min_entries);
1968 	}
1969 	rrl->max_entries = i;
1970 
1971 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
1972 		       "responses-per-second");
1973 	CHECK_RRL_RATE(referrals_per_second,
1974 		       rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
1975 		       "referrals-per-second");
1976 	CHECK_RRL_RATE(nodata_per_second,
1977 		       rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
1978 		       "nodata-per-second");
1979 	CHECK_RRL_RATE(nxdomains_per_second,
1980 		       rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
1981 		       "nxdomains-per-second");
1982 	CHECK_RRL_RATE(errors_per_second,
1983 		       rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
1984 		       "errors-per-second");
1985 
1986 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
1987 		       "all-per-second");
1988 
1989 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP,
1990 		       "slip");
1991 
1992 	i = 15;
1993 	obj = NULL;
1994 	result = cfg_map_get(map, "window", &obj);
1995 	if (result == ISC_R_SUCCESS) {
1996 		i = cfg_obj_asuint32(obj);
1997 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
1998 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
1999 	}
2000 	rrl->window = i;
2001 
2002 	i = 0;
2003 	obj = NULL;
2004 	result = cfg_map_get(map, "qps-scale", &obj);
2005 	if (result == ISC_R_SUCCESS) {
2006 		i = cfg_obj_asuint32(obj);
2007 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
2008 	}
2009 	rrl->qps_scale = i;
2010 	rrl->qps = 1.0;
2011 
2012 	i = 24;
2013 	obj = NULL;
2014 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
2015 	if (result == ISC_R_SUCCESS) {
2016 		i = cfg_obj_asuint32(obj);
2017 		CHECK_RRL(i >= 8 && i <= 32,
2018 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
2019 	}
2020 	rrl->ipv4_prefixlen = i;
2021 	if (i == 32)
2022 		rrl->ipv4_mask = 0xffffffff;
2023 	else
2024 		rrl->ipv4_mask = htonl(0xffffffff << (32-i));
2025 
2026 	i = 56;
2027 	obj = NULL;
2028 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
2029 	if (result == ISC_R_SUCCESS) {
2030 		i = cfg_obj_asuint32(obj);
2031 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
2032 			  "ipv6-prefix-length %d < 16 or > %d",
2033 			  i, DNS_RRL_MAX_PREFIX);
2034 	}
2035 	rrl->ipv6_prefixlen = i;
2036 	for (j = 0; j < 4; ++j) {
2037 		if (i <= 0) {
2038 			rrl->ipv6_mask[j] = 0;
2039 		} else if (i < 32) {
2040 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i));
2041 		} else {
2042 			rrl->ipv6_mask[j] = 0xffffffff;
2043 		}
2044 		i -= 32;
2045 	}
2046 
2047 	obj = NULL;
2048 	result = cfg_map_get(map, "exempt-clients", &obj);
2049 	if (result == ISC_R_SUCCESS) {
2050 		result = cfg_acl_fromconfig(obj, config, ns_g_lctx,
2051 					    ns_g_aclconfctx, ns_g_mctx,
2052 					    0, &rrl->exempt);
2053 		CHECK_RRL(result == ISC_R_SUCCESS,
2054 			  "invalid %s%s", "address match list", "");
2055 	}
2056 
2057 	obj = NULL;
2058 	result = cfg_map_get(map, "log-only", &obj);
2059 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj))
2060 		rrl->log_only = ISC_TRUE;
2061 	else
2062 		rrl->log_only = ISC_FALSE;
2063 
2064 	return (ISC_R_SUCCESS);
2065 
2066  cleanup:
2067 	dns_rrl_view_destroy(view);
2068 	return (result);
2069 }
2070 
2071 static isc_result_t
2072 add_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
2073 	dns_name_t *origin, dns_name_t *contact)
2074 {
2075 	dns_dbnode_t *node = NULL;
2076 	dns_rdata_t rdata = DNS_RDATA_INIT;
2077 	dns_rdatalist_t rdatalist;
2078 	dns_rdataset_t rdataset;
2079 	isc_result_t result;
2080 	unsigned char buf[DNS_SOA_BUFFERSIZE];
2081 
2082 	dns_rdataset_init(&rdataset);
2083 	dns_rdatalist_init(&rdatalist);
2084 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
2085 				 0, 28800, 7200, 604800, 86400, buf, &rdata));
2086 	rdatalist.type = rdata.type;
2087 	rdatalist.covers = 0;
2088 	rdatalist.rdclass = rdata.rdclass;
2089 	rdatalist.ttl = 86400;
2090 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
2091 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
2092 	CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
2093 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
2094  cleanup:
2095 	if (node != NULL)
2096 		dns_db_detachnode(db, &node);
2097 	return (result);
2098 }
2099 
2100 static isc_result_t
2101 add_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
2102        dns_name_t *nsname)
2103 {
2104 	dns_dbnode_t *node = NULL;
2105 	dns_rdata_ns_t ns;
2106 	dns_rdata_t rdata = DNS_RDATA_INIT;
2107 	dns_rdatalist_t rdatalist;
2108 	dns_rdataset_t rdataset;
2109 	isc_result_t result;
2110 	isc_buffer_t b;
2111 	unsigned char buf[DNS_NAME_MAXWIRE];
2112 
2113 	isc_buffer_init(&b, buf, sizeof(buf));
2114 
2115 	dns_rdataset_init(&rdataset);
2116 	dns_rdatalist_init(&rdatalist);
2117 	ns.common.rdtype = dns_rdatatype_ns;
2118 	ns.common.rdclass = dns_db_class(db);
2119 	ns.mctx = NULL;
2120 	dns_name_init(&ns.name, NULL);
2121 	dns_name_clone(nsname, &ns.name);
2122 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
2123 				   &ns, &b));
2124 	rdatalist.type = rdata.type;
2125 	rdatalist.covers = 0;
2126 	rdatalist.rdclass = rdata.rdclass;
2127 	rdatalist.ttl = 86400;
2128 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
2129 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
2130 	CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
2131 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
2132  cleanup:
2133 	if (node != NULL)
2134 		dns_db_detachnode(db, &node);
2135 	return (result);
2136 }
2137 
2138 static isc_result_t
2139 create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
2140 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
2141 		  int empty_dbtypec, dns_zonestat_level_t statlevel)
2142 {
2143 	char namebuf[DNS_NAME_FORMATSIZE];
2144 	const cfg_listelt_t *element;
2145 	const cfg_obj_t *obj;
2146 	const cfg_obj_t *zconfig;
2147 	const cfg_obj_t *zoptions;
2148 	const char *rbt_dbtype[4] = { "rbt" };
2149 	const char *sep = ": view ";
2150 	const char *str;
2151 	const char *viewname = view->name;
2152 	dns_db_t *db = NULL;
2153 	dns_dbversion_t *version = NULL;
2154 	dns_fixedname_t cfixed;
2155 	dns_fixedname_t fixed;
2156 	dns_fixedname_t nsfixed;
2157 	dns_name_t *contact;
2158 	dns_name_t *ns;
2159 	dns_name_t *zname;
2160 	dns_zone_t *myzone = NULL;
2161 	int rbt_dbtypec = 1;
2162 	isc_result_t result;
2163 	dns_namereln_t namereln;
2164 	int order;
2165 	unsigned int nlabels;
2166 
2167 	dns_fixedname_init(&fixed);
2168 	zname = dns_fixedname_name(&fixed);
2169 	dns_fixedname_init(&nsfixed);
2170 	ns = dns_fixedname_name(&nsfixed);
2171 	dns_fixedname_init(&cfixed);
2172 	contact = dns_fixedname_name(&cfixed);
2173 
2174 	/*
2175 	 * Look for forward "zones" beneath this empty zone and if so
2176 	 * create a custom db for the empty zone.
2177 	 */
2178 	for (element = cfg_list_first(zonelist);
2179 	     element != NULL;
2180 	     element = cfg_list_next(element)) {
2181 
2182 		zconfig = cfg_listelt_value(element);
2183 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
2184 		CHECK(dns_name_fromstring(zname, str, 0, NULL));
2185 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
2186 		if (namereln != dns_namereln_subdomain)
2187 			continue;
2188 
2189 		zoptions = cfg_tuple_get(zconfig, "options");
2190 
2191 		obj = NULL;
2192 		(void)cfg_map_get(zoptions, "type", &obj);
2193 		INSIST(obj != NULL);
2194 		if (strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
2195 			obj = NULL;
2196 			(void)cfg_map_get(zoptions, "forward", &obj);
2197 			if (obj == NULL)
2198 				continue;
2199 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0)
2200 				continue;
2201 		}
2202 		if (db == NULL) {
2203 			CHECK(dns_db_create(view->mctx, "rbt", name,
2204 					    dns_dbtype_zone, view->rdclass,
2205 					    0, NULL, &db));
2206 			CHECK(dns_db_newversion(db, &version));
2207 			if (strcmp(empty_dbtype[2], "@") == 0)
2208 				dns_name_clone(name, ns);
2209 			else
2210 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
2211 							  0, NULL));
2212 			CHECK(dns_name_fromstring(contact, empty_dbtype[3],
2213 						  0, NULL));
2214 			CHECK(add_soa(db, version, name, ns, contact));
2215 			CHECK(add_ns(db, version, name, ns));
2216 		}
2217 		CHECK(add_ns(db, version, zname, dns_rootname));
2218 	}
2219 
2220 	/*
2221 	 * Is the existing zone the ok to use?
2222 	 */
2223 	if (zone != NULL) {
2224 		unsigned int typec;
2225 		const char **dbargv;
2226 
2227 		if (db != NULL) {
2228 			typec = rbt_dbtypec;
2229 			dbargv = rbt_dbtype;
2230 		} else {
2231 			typec = empty_dbtypec;
2232 			dbargv = empty_dbtype;
2233 		}
2234 
2235 		result = check_dbtype(zone, typec, dbargv, view->mctx);
2236 		if (result != ISC_R_SUCCESS)
2237 			zone = NULL;
2238 
2239 		if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master)
2240 			zone = NULL;
2241 		if (zone != NULL && dns_zone_getfile(zone) != NULL)
2242 			zone = NULL;
2243 		if (zone != NULL) {
2244 			dns_zone_getraw(zone, &myzone);
2245 			if (myzone != NULL) {
2246 				dns_zone_detach(&myzone);
2247 				zone = NULL;
2248 			}
2249 		}
2250 	}
2251 
2252 	if (zone == NULL) {
2253 		CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &myzone));
2254 		zone = myzone;
2255 		CHECK(dns_zone_setorigin(zone, name));
2256 		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
2257 		if (db == NULL)
2258 			CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
2259 						 empty_dbtype));
2260 		dns_zone_setclass(zone, view->rdclass);
2261 		dns_zone_settype(zone, dns_zone_master);
2262 		dns_zone_setstats(zone, ns_g_server->zonestats);
2263 	}
2264 
2265 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, ISC_FALSE);
2266 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
2267 	dns_zone_setnotifytype(zone, dns_notifytype_no);
2268 	dns_zone_setdialup(zone, dns_dialuptype_no);
2269 	if (view->queryacl != NULL)
2270 		dns_zone_setqueryacl(zone, view->queryacl);
2271 	else
2272 		dns_zone_clearqueryacl(zone);
2273 	if (view->queryonacl != NULL)
2274 		dns_zone_setqueryonacl(zone, view->queryonacl);
2275 	else
2276 		dns_zone_clearqueryonacl(zone);
2277 	dns_zone_clearupdateacl(zone);
2278 	if (view->transferacl != NULL)
2279 		dns_zone_setxfracl(zone, view->transferacl);
2280 	else
2281 		dns_zone_clearxfracl(zone);
2282 
2283 	CHECK(setquerystats(zone, view->mctx, statlevel));
2284 	if (db != NULL) {
2285 		dns_db_closeversion(db, &version, ISC_TRUE);
2286 		CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
2287 	}
2288 	dns_zone_setview(zone, view);
2289 	CHECK(dns_view_addzone(view, zone));
2290 
2291 	if (!strcmp(viewname, "_default")) {
2292 		sep = "";
2293 		viewname = "";
2294 	}
2295 	dns_name_format(name, namebuf, sizeof(namebuf));
2296 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2297 		      ISC_LOG_INFO, "automatic empty zone%s%s: %s",
2298 		      sep, viewname, namebuf);
2299 
2300  cleanup:
2301 	if (myzone != NULL)
2302 		dns_zone_detach(&myzone);
2303 	if (version != NULL)
2304 		dns_db_closeversion(db, &version, ISC_FALSE);
2305 	if (db != NULL)
2306 		dns_db_detach(&db);
2307 
2308 	INSIST(version == NULL);
2309 
2310 	return (result);
2311 }
2312 
2313 /*
2314  * Configure 'view' according to 'vconfig', taking defaults from 'config'
2315  * where values are missing in 'vconfig'.
2316  *
2317  * When configuring the default view, 'vconfig' will be NULL and the
2318  * global defaults in 'config' used exclusively.
2319  */
2320 static isc_result_t
2321 configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
2322 	       cfg_obj_t *config, cfg_obj_t *vconfig,
2323 	       ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
2324 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx,
2325 	       isc_boolean_t need_hints)
2326 {
2327 	const cfg_obj_t *maps[4];
2328 	const cfg_obj_t *cfgmaps[3];
2329 	const cfg_obj_t *optionmaps[3];
2330 	const cfg_obj_t *options = NULL;
2331 	const cfg_obj_t *voptions = NULL;
2332 	const cfg_obj_t *forwardtype;
2333 	const cfg_obj_t *forwarders;
2334 	const cfg_obj_t *alternates;
2335 	const cfg_obj_t *zonelist;
2336 	const cfg_obj_t *dlzlist;
2337 	const cfg_obj_t *dlz;
2338 	unsigned int dlzargc;
2339 	char **dlzargv;
2340 	const cfg_obj_t *disabled;
2341 	const cfg_obj_t *obj;
2342 	const cfg_listelt_t *element;
2343 	in_port_t port;
2344 	dns_cache_t *cache = NULL;
2345 	isc_result_t result;
2346 	unsigned int cleaning_interval;
2347 	size_t max_cache_size;
2348 	size_t max_acache_size;
2349 	size_t max_adb_size;
2350 	isc_uint32_t lame_ttl;
2351 	dns_tsig_keyring_t *ring = NULL;
2352 	dns_view_t *pview = NULL;	/* Production view */
2353 	isc_mem_t *cmctx = NULL, *hmctx = NULL;
2354 	dns_dispatch_t *dispatch4 = NULL;
2355 	dns_dispatch_t *dispatch6 = NULL;
2356 	isc_boolean_t reused_cache = ISC_FALSE;
2357 	isc_boolean_t shared_cache = ISC_FALSE;
2358 	int i = 0, j = 0, k = 0;
2359 	const char *str;
2360 	const char *cachename = NULL;
2361 	dns_order_t *order = NULL;
2362 	isc_uint32_t udpsize;
2363 	isc_uint32_t maxbits;
2364 	unsigned int resopts = 0;
2365 	dns_zone_t *zone = NULL;
2366 	isc_uint32_t max_clients_per_query;
2367 	isc_boolean_t empty_zones_enable;
2368 	const cfg_obj_t *disablelist = NULL;
2369 	isc_stats_t *resstats = NULL;
2370 	dns_stats_t *resquerystats = NULL;
2371 	isc_boolean_t auto_dlv = ISC_FALSE;
2372 	isc_boolean_t auto_root = ISC_FALSE;
2373 	ns_cache_t *nsc;
2374 	isc_boolean_t zero_no_soattl;
2375 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
2376 	unsigned int query_timeout, ndisp;
2377 	struct cfg_context *nzctx;
2378 	isc_boolean_t old_rpz_ok = ISC_FALSE;
2379 	isc_dscp_t dscp4 = -1, dscp6 = -1;
2380 
2381 	REQUIRE(DNS_VIEW_VALID(view));
2382 
2383 	if (config != NULL)
2384 		(void)cfg_map_get(config, "options", &options);
2385 
2386 	/*
2387 	 * maps: view options, options, defaults
2388 	 * cfgmaps: view options, config
2389 	 * optionmaps: view options, options
2390 	 */
2391 	if (vconfig != NULL) {
2392 		voptions = cfg_tuple_get(vconfig, "options");
2393 		maps[i++] = voptions;
2394 		optionmaps[j++] = voptions;
2395 		cfgmaps[k++] = voptions;
2396 	}
2397 	if (options != NULL) {
2398 		maps[i++] = options;
2399 		optionmaps[j++] = options;
2400 	}
2401 
2402 	maps[i++] = ns_g_defaults;
2403 	maps[i] = NULL;
2404 	optionmaps[j] = NULL;
2405 	if (config != NULL)
2406 		cfgmaps[k++] = config;
2407 	cfgmaps[k] = NULL;
2408 
2409 	/*
2410 	 * Set the view's port number for outgoing queries.
2411 	 */
2412 	CHECKM(ns_config_getport(config, &port), "port");
2413 	dns_view_setdstport(view, port);
2414 
2415 	/*
2416 	 * Create additional cache for this view and zones under the view
2417 	 * if explicitly enabled.
2418 	 * XXX950 default to on.
2419 	 */
2420 	obj = NULL;
2421 	(void)ns_config_get(maps, "acache-enable", &obj);
2422 	if (obj != NULL && cfg_obj_asboolean(obj)) {
2423 		cmctx = NULL;
2424 		CHECK(isc_mem_create(0, 0, &cmctx));
2425 		CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
2426 					ns_g_timermgr));
2427 		isc_mem_setname(cmctx, "acache", NULL);
2428 		isc_mem_detach(&cmctx);
2429 	}
2430 	if (view->acache != NULL) {
2431 		obj = NULL;
2432 		result = ns_config_get(maps, "acache-cleaning-interval", &obj);
2433 		INSIST(result == ISC_R_SUCCESS);
2434 		dns_acache_setcleaninginterval(view->acache,
2435 					       cfg_obj_asuint32(obj) * 60);
2436 
2437 		obj = NULL;
2438 		result = ns_config_get(maps, "max-acache-size", &obj);
2439 		INSIST(result == ISC_R_SUCCESS);
2440 		if (cfg_obj_isstring(obj)) {
2441 			str = cfg_obj_asstring(obj);
2442 			INSIST(strcasecmp(str, "unlimited") == 0);
2443 			max_acache_size = 0;
2444 		} else {
2445 			isc_resourcevalue_t value;
2446 			value = cfg_obj_asuint64(obj);
2447 			if (value > SIZE_MAX) {
2448 				cfg_obj_log(obj, ns_g_lctx,
2449 					    ISC_LOG_WARNING,
2450 					    "'max-acache-size "
2451 					    "%" ISC_PRINT_QUADFORMAT "u' "
2452 					    "is too large for this "
2453 					    "system; reducing to %lu",
2454 					    value, (unsigned long)SIZE_MAX);
2455 				value = SIZE_MAX;
2456 			}
2457 			max_acache_size = (size_t) value;
2458 		}
2459 		dns_acache_setcachesize(view->acache, max_acache_size);
2460 	}
2461 
2462 	CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
2463 				 ns_g_mctx, &view->queryacl));
2464 	if (view->queryacl == NULL) {
2465 		CHECK(configure_view_acl(NULL, ns_g_config, "allow-query",
2466 					 NULL, actx, ns_g_mctx,
2467 					 &view->queryacl));
2468 	}
2469 
2470 	/*
2471 	 * Make the list of response policy zone names for a view that
2472 	 * is used for real lookups and so cares about hints.
2473 	 */
2474 	obj = NULL;
2475 	if (view->rdclass == dns_rdataclass_in && need_hints &&
2476 	    ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
2477 		CHECK(configure_rpz(view, obj, &old_rpz_ok));
2478 	}
2479 
2480 	/*
2481 	 * Configure the zones.
2482 	 */
2483 	zonelist = NULL;
2484 	if (voptions != NULL)
2485 		(void)cfg_map_get(voptions, "zone", &zonelist);
2486 	else
2487 		(void)cfg_map_get(config, "zone", &zonelist);
2488 
2489 	/*
2490 	 * Load zone configuration
2491 	 */
2492 	for (element = cfg_list_first(zonelist);
2493 	     element != NULL;
2494 	     element = cfg_list_next(element))
2495 	{
2496 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
2497 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
2498 				     viewlist, actx, ISC_FALSE, old_rpz_ok));
2499 	}
2500 
2501 	/*
2502 	 * Check that a master or slave zone was found for each
2503 	 * zone named in the response policy statement.
2504 	 */
2505 	if (view->rpzs != NULL) {
2506 		dns_rpz_num_t n;
2507 
2508 		for (n = 0; n < view->rpzs->p.num_zones; ++n)
2509 		{
2510 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
2511 				char namebuf[DNS_NAME_FORMATSIZE];
2512 
2513 				dns_name_format(&view->rpzs->zones[n]->origin,
2514 						namebuf, sizeof(namebuf));
2515 				cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
2516 					    "'%s' is not a master or slave zone",
2517 					    namebuf);
2518 				result = ISC_R_NOTFOUND;
2519 				goto cleanup;
2520 			}
2521 		}
2522 	}
2523 
2524 	/*
2525 	 * If we're allowing added zones, then load zone configuration
2526 	 * from the newzone file for zones that were added during previous
2527 	 * runs.
2528 	 */
2529 	nzctx = view->new_zone_config;
2530 	if (nzctx != NULL && nzctx->nzconfig != NULL) {
2531 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2532 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2533 			      "loading additional zones for view '%s'",
2534 			      view->name);
2535 
2536 		zonelist = NULL;
2537 		cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
2538 
2539 		for (element = cfg_list_first(zonelist);
2540 		     element != NULL;
2541 		     element = cfg_list_next(element))
2542 		{
2543 			const cfg_obj_t *zconfig = cfg_listelt_value(element);
2544 			CHECK(configure_zone(config, zconfig, vconfig,
2545 					     mctx, view, NULL, actx,
2546 					     ISC_TRUE, ISC_FALSE));
2547 		}
2548 	}
2549 
2550 	/*
2551 	 * Create Dynamically Loadable Zone driver.
2552 	 */
2553 	dlzlist = NULL;
2554 	if (voptions != NULL)
2555 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
2556 	else
2557 		(void)cfg_map_get(config, "dlz", &dlzlist);
2558 
2559 	for (element = cfg_list_first(dlzlist);
2560 	     element != NULL;
2561 	     element = cfg_list_next(element))
2562 	{
2563 		dlz = cfg_listelt_value(element);
2564 
2565 		obj = NULL;
2566 		(void)cfg_map_get(dlz, "database", &obj);
2567 		if (obj != NULL) {
2568 			dns_dlzdb_t *dlzdb = NULL;
2569 			const cfg_obj_t *name, *search = NULL;
2570 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
2571 
2572 			if (s == NULL) {
2573 				result = ISC_R_NOMEMORY;
2574 				goto cleanup;
2575 			}
2576 
2577 			result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
2578 			if (result != ISC_R_SUCCESS) {
2579 				isc_mem_free(mctx, s);
2580 				goto cleanup;
2581 			}
2582 
2583 			name = cfg_map_getname(dlz);
2584 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
2585 					       dlzargv[0], dlzargc, dlzargv,
2586 					       &dlzdb);
2587 			isc_mem_free(mctx, s);
2588 			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
2589 			if (result != ISC_R_SUCCESS)
2590 				goto cleanup;
2591 
2592 			/*
2593 			 * If the DLZ backend supports configuration,
2594 			 * and is searchable, then call its configure
2595 			 * method now.  If not searchable, we'll take
2596 			 * care of it when we process the zone statement.
2597 			 */
2598 			(void)cfg_map_get(dlz, "search", &search);
2599 			if (search == NULL || cfg_obj_asboolean(search)) {
2600 				dlzdb->search = ISC_TRUE;
2601 				result = dns_dlzconfigure(view, dlzdb,
2602 							dlzconfigure_callback);
2603 				if (result != ISC_R_SUCCESS)
2604 					goto cleanup;
2605 				ISC_LIST_APPEND(view->dlz_searched,
2606 						dlzdb, link);
2607 			} else {
2608 				dlzdb->search = ISC_FALSE;
2609 				ISC_LIST_APPEND(view->dlz_unsearched,
2610 						dlzdb, link);
2611 			}
2612 
2613 		}
2614 	}
2615 
2616 	/*
2617 	 * Obtain configuration parameters that affect the decision of whether
2618 	 * we can reuse/share an existing cache.
2619 	 */
2620 	obj = NULL;
2621 	result = ns_config_get(maps, "cleaning-interval", &obj);
2622 	INSIST(result == ISC_R_SUCCESS);
2623 	cleaning_interval = cfg_obj_asuint32(obj) * 60;
2624 
2625 	obj = NULL;
2626 	result = ns_config_get(maps, "max-cache-size", &obj);
2627 	INSIST(result == ISC_R_SUCCESS);
2628 	if (cfg_obj_isstring(obj)) {
2629 		str = cfg_obj_asstring(obj);
2630 		INSIST(strcasecmp(str, "unlimited") == 0);
2631 		max_cache_size = 0;
2632 	} else {
2633 		isc_resourcevalue_t value;
2634 		value = cfg_obj_asuint64(obj);
2635 		if (value > SIZE_MAX) {
2636 			cfg_obj_log(obj, ns_g_lctx,
2637 				    ISC_LOG_WARNING,
2638 				    "'max-cache-size "
2639 				    "%" ISC_PRINT_QUADFORMAT "u' "
2640 				    "is too large for this "
2641 				    "system; reducing to %lu",
2642 				    value, (unsigned long)SIZE_MAX);
2643 			value = SIZE_MAX;
2644 		}
2645 		max_cache_size = (size_t) value;
2646 	}
2647 
2648 	/* Check-names. */
2649 	obj = NULL;
2650 	result = ns_checknames_get(maps, "response", &obj);
2651 	INSIST(result == ISC_R_SUCCESS);
2652 
2653 	str = cfg_obj_asstring(obj);
2654 	if (strcasecmp(str, "fail") == 0) {
2655 		resopts |= DNS_RESOLVER_CHECKNAMES |
2656 			DNS_RESOLVER_CHECKNAMESFAIL;
2657 		view->checknames = ISC_TRUE;
2658 	} else if (strcasecmp(str, "warn") == 0) {
2659 		resopts |= DNS_RESOLVER_CHECKNAMES;
2660 		view->checknames = ISC_FALSE;
2661 	} else if (strcasecmp(str, "ignore") == 0) {
2662 		view->checknames = ISC_FALSE;
2663 	} else
2664 		INSIST(0);
2665 
2666 	obj = NULL;
2667 	result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
2668 	INSIST(result == ISC_R_SUCCESS);
2669 	zero_no_soattl = cfg_obj_asboolean(obj);
2670 
2671 	obj = NULL;
2672 	result = ns_config_get(maps, "dns64", &obj);
2673 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
2674 	    strcmp(view->name, "_meta")) {
2675 		isc_netaddr_t na, suffix, *sp;
2676 		unsigned int prefixlen;
2677 		const char *server, *contact;
2678 		const cfg_obj_t *myobj;
2679 
2680 		myobj = NULL;
2681 		result = ns_config_get(maps, "dns64-server", &myobj);
2682 		if (result == ISC_R_SUCCESS)
2683 			server = cfg_obj_asstring(myobj);
2684 		else
2685 			server = NULL;
2686 
2687 		myobj = NULL;
2688 		result = ns_config_get(maps, "dns64-contact", &myobj);
2689 		if (result == ISC_R_SUCCESS)
2690 			contact = cfg_obj_asstring(myobj);
2691 		else
2692 			contact = NULL;
2693 
2694 		for (element = cfg_list_first(obj);
2695 		     element != NULL;
2696 		     element = cfg_list_next(element))
2697 		{
2698 			const cfg_obj_t *map = cfg_listelt_value(element);
2699 			dns_dns64_t *dns64 = NULL;
2700 			unsigned int dns64options = 0;
2701 
2702 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
2703 					    &prefixlen);
2704 
2705 			obj = NULL;
2706 			(void)cfg_map_get(map, "suffix", &obj);
2707 			if (obj != NULL) {
2708 				sp = &suffix;
2709 				isc_netaddr_fromsockaddr(sp,
2710 						      cfg_obj_assockaddr(obj));
2711 			} else
2712 				sp = NULL;
2713 
2714 			clients = mapped = excluded = NULL;
2715 			obj = NULL;
2716 			(void)cfg_map_get(map, "clients", &obj);
2717 			if (obj != NULL) {
2718 				result = cfg_acl_fromconfig(obj, config,
2719 							    ns_g_lctx, actx,
2720 							    mctx, 0, &clients);
2721 				if (result != ISC_R_SUCCESS)
2722 					goto cleanup;
2723 			}
2724 			obj = NULL;
2725 			(void)cfg_map_get(map, "mapped", &obj);
2726 			if (obj != NULL) {
2727 				result = cfg_acl_fromconfig(obj, config,
2728 							    ns_g_lctx, actx,
2729 							    mctx, 0, &mapped);
2730 				if (result != ISC_R_SUCCESS)
2731 					goto cleanup;
2732 			}
2733 			obj = NULL;
2734 			(void)cfg_map_get(map, "exclude", &obj);
2735 			if (obj != NULL) {
2736 				result = cfg_acl_fromconfig(obj, config,
2737 							    ns_g_lctx, actx,
2738 							    mctx, 0, &excluded);
2739 				if (result != ISC_R_SUCCESS)
2740 					goto cleanup;
2741 			}
2742 
2743 			obj = NULL;
2744 			(void)cfg_map_get(map, "recursive-only", &obj);
2745 			if (obj != NULL && cfg_obj_asboolean(obj))
2746 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
2747 
2748 			obj = NULL;
2749 			(void)cfg_map_get(map, "break-dnssec", &obj);
2750 			if (obj != NULL && cfg_obj_asboolean(obj))
2751 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
2752 
2753 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
2754 						  clients, mapped, excluded,
2755 						  dns64options, &dns64);
2756 			if (result != ISC_R_SUCCESS)
2757 				goto cleanup;
2758 			dns_dns64_append(&view->dns64, dns64);
2759 			view->dns64cnt++;
2760 			result = dns64_reverse(view, mctx, &na, prefixlen,
2761 					       server, contact);
2762 			if (result != ISC_R_SUCCESS)
2763 				goto cleanup;
2764 			if (clients != NULL)
2765 				dns_acl_detach(&clients);
2766 			if (mapped != NULL)
2767 				dns_acl_detach(&mapped);
2768 			if (excluded != NULL)
2769 				dns_acl_detach(&excluded);
2770 		}
2771 	}
2772 
2773 	obj = NULL;
2774 	result = ns_config_get(maps, "dnssec-accept-expired", &obj);
2775 	INSIST(result == ISC_R_SUCCESS);
2776 	view->acceptexpired = cfg_obj_asboolean(obj);
2777 
2778 	obj = NULL;
2779 	result = ns_config_get(maps, "dnssec-validation", &obj);
2780 	INSIST(result == ISC_R_SUCCESS);
2781 	if (cfg_obj_isboolean(obj)) {
2782 		view->enablevalidation = cfg_obj_asboolean(obj);
2783 	} else {
2784 		/* If dnssec-validation is not boolean, it must be "auto" */
2785 		view->enablevalidation = ISC_TRUE;
2786 		auto_root = ISC_TRUE;
2787 	}
2788 
2789 	obj = NULL;
2790 	result = ns_config_get(maps, "max-cache-ttl", &obj);
2791 	INSIST(result == ISC_R_SUCCESS);
2792 	view->maxcachettl = cfg_obj_asuint32(obj);
2793 
2794 	obj = NULL;
2795 	result = ns_config_get(maps, "max-ncache-ttl", &obj);
2796 	INSIST(result == ISC_R_SUCCESS);
2797 	view->maxncachettl = cfg_obj_asuint32(obj);
2798 	if (view->maxncachettl > 7 * 24 * 3600)
2799 		view->maxncachettl = 7 * 24 * 3600;
2800 
2801 	/*
2802 	 * Configure the view's cache.
2803 	 *
2804 	 * First, check to see if there are any attach-cache options.  If yes,
2805 	 * attempt to lookup an existing cache at attach it to the view.  If
2806 	 * there is not one, then try to reuse an existing cache if possible;
2807 	 * otherwise create a new cache.
2808 	 *
2809 	 * Note that the ADB is not preserved or shared in either case.
2810 	 *
2811 	 * When a matching view is found, the associated statistics are also
2812 	 * retrieved and reused.
2813 	 *
2814 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
2815 	 * When the view's configuration changes, the cached data may become
2816 	 * invalid because it reflects our old view of the world.  We check
2817 	 * some of the configuration parameters that could invalidate the cache
2818 	 * or otherwise make it unsharable, but there are other configuration
2819 	 * options that should be checked.  For example, if a view uses a
2820 	 * forwarder, changes in the forwarder configuration may invalidate
2821 	 * the cache.  At the moment, it's the administrator's responsibility to
2822 	 * ensure these configuration options don't invalidate reusing/sharing.
2823 	 */
2824 	obj = NULL;
2825 	result = ns_config_get(maps, "attach-cache", &obj);
2826 	if (result == ISC_R_SUCCESS)
2827 		cachename = cfg_obj_asstring(obj);
2828 	else
2829 		cachename = view->name;
2830 	cache = NULL;
2831 	nsc = cachelist_find(cachelist, cachename);
2832 	if (nsc != NULL) {
2833 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
2834 				    cleaning_interval, max_cache_size)) {
2835 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2836 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2837 				      "views %s and %s can't share the cache "
2838 				      "due to configuration parameter mismatch",
2839 				      nsc->primaryview->name, view->name);
2840 			result = ISC_R_FAILURE;
2841 			goto cleanup;
2842 		}
2843 		dns_cache_attach(nsc->cache, &cache);
2844 		shared_cache = ISC_TRUE;
2845 	} else {
2846 		if (strcmp(cachename, view->name) == 0) {
2847 			result = dns_viewlist_find(&ns_g_server->viewlist,
2848 						   cachename, view->rdclass,
2849 						   &pview);
2850 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2851 				goto cleanup;
2852 			if (pview != NULL) {
2853 				if (!cache_reusable(pview, view,
2854 						    zero_no_soattl)) {
2855 					isc_log_write(ns_g_lctx,
2856 						      NS_LOGCATEGORY_GENERAL,
2857 						      NS_LOGMODULE_SERVER,
2858 						      ISC_LOG_DEBUG(1),
2859 						      "cache cannot be reused "
2860 						      "for view %s due to "
2861 						      "configuration parameter "
2862 						      "mismatch", view->name);
2863 				} else {
2864 					INSIST(pview->cache != NULL);
2865 					isc_log_write(ns_g_lctx,
2866 						      NS_LOGCATEGORY_GENERAL,
2867 						      NS_LOGMODULE_SERVER,
2868 						      ISC_LOG_DEBUG(3),
2869 						      "reusing existing cache");
2870 					reused_cache = ISC_TRUE;
2871 					dns_cache_attach(pview->cache, &cache);
2872 				}
2873 				dns_view_getresstats(pview, &resstats);
2874 				dns_view_getresquerystats(pview,
2875 							  &resquerystats);
2876 				dns_view_detach(&pview);
2877 			}
2878 		}
2879 		if (cache == NULL) {
2880 			/*
2881 			 * Create a cache with the desired name.  This normally
2882 			 * equals the view name, but may also be a forward
2883 			 * reference to a view that share the cache with this
2884 			 * view but is not yet configured.  If it is not the
2885 			 * view name but not a forward reference either, then it
2886 			 * is simply a named cache that is not shared.
2887 			 *
2888 			 * We use two separate memory contexts for the
2889 			 * cache, for the main cache memory and the heap
2890 			 * memory.
2891 			 */
2892 			CHECK(isc_mem_create(0, 0, &cmctx));
2893 			isc_mem_setname(cmctx, "cache", NULL);
2894 			CHECK(isc_mem_create(0, 0, &hmctx));
2895 			isc_mem_setname(hmctx, "cache_heap", NULL);
2896 			CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr,
2897 						ns_g_timermgr, view->rdclass,
2898 						cachename, "rbt", 0, NULL,
2899 						&cache));
2900 			isc_mem_detach(&cmctx);
2901 			isc_mem_detach(&hmctx);
2902 		}
2903 		nsc = isc_mem_get(mctx, sizeof(*nsc));
2904 		if (nsc == NULL) {
2905 			result = ISC_R_NOMEMORY;
2906 			goto cleanup;
2907 		}
2908 		nsc->cache = NULL;
2909 		dns_cache_attach(cache, &nsc->cache);
2910 		nsc->primaryview = view;
2911 		nsc->needflush = ISC_FALSE;
2912 		nsc->adbsizeadjusted = ISC_FALSE;
2913 		ISC_LINK_INIT(nsc, link);
2914 		ISC_LIST_APPEND(*cachelist, nsc, link);
2915 	}
2916 	dns_view_setcache2(view, cache, shared_cache);
2917 
2918 	/*
2919 	 * cache-file cannot be inherited if views are present, but this
2920 	 * should be caught by the configuration checking stage.
2921 	 */
2922 	obj = NULL;
2923 	result = ns_config_get(maps, "cache-file", &obj);
2924 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
2925 		CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
2926 		if (!reused_cache && !shared_cache)
2927 			CHECK(dns_cache_load(cache));
2928 	}
2929 
2930 	dns_cache_setcleaninginterval(cache, cleaning_interval);
2931 	dns_cache_setcachesize(cache, max_cache_size);
2932 
2933 	dns_cache_detach(&cache);
2934 
2935 	/*
2936 	 * Resolver.
2937 	 *
2938 	 * XXXRTH  Hardwired number of tasks.
2939 	 */
2940 	CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, &dscp4,
2941 					    ISC_TF(ISC_LIST_PREV(view, link)
2942 						   == NULL)));
2943 	CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, &dscp6,
2944 					    ISC_TF(ISC_LIST_PREV(view, link)
2945 						   == NULL)));
2946 	if (dispatch4 == NULL && dispatch6 == NULL) {
2947 		UNEXPECTED_ERROR(__FILE__, __LINE__,
2948 				 "unable to obtain neither an IPv4 nor"
2949 				 " an IPv6 dispatch");
2950 		result = ISC_R_UNEXPECTED;
2951 		goto cleanup;
2952 	}
2953 
2954 	if (resstats == NULL) {
2955 		CHECK(isc_stats_create(mctx, &resstats,
2956 				       dns_resstatscounter_max));
2957 	}
2958 	dns_view_setresstats(view, resstats);
2959 	if (resquerystats == NULL)
2960 		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
2961 	dns_view_setresquerystats(view, resquerystats);
2962 
2963 	ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
2964 	CHECK(dns_view_createresolver(view, ns_g_taskmgr, RESOLVER_NTASKS,
2965 				      ndisp, ns_g_socketmgr, ns_g_timermgr,
2966 				      resopts, ns_g_dispatchmgr,
2967 				      dispatch4, dispatch6));
2968 
2969 	if (dscp4 == -1)
2970 		dscp4 = ns_g_dscp;
2971 	if (dscp6 == -1)
2972 		dscp6 = ns_g_dscp;
2973 	if (dscp4 != -1)
2974 		dns_resolver_setquerydscp4(view->resolver, dscp4);
2975 	if (dscp6 != -1)
2976 		dns_resolver_setquerydscp6(view->resolver, dscp6);
2977 
2978 	/*
2979 	 * Set the ADB cache size to 1/8th of the max-cache-size or
2980 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
2981 	 */
2982 	max_adb_size = 0;
2983 	if (max_cache_size != 0U) {
2984 		max_adb_size = max_cache_size / 8;
2985 		if (max_adb_size == 0U)
2986 			max_adb_size = 1;	/* Force minimum. */
2987 		if (view != nsc->primaryview &&
2988 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
2989 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
2990 			if (!nsc->adbsizeadjusted) {
2991 				dns_adb_setadbsize(nsc->primaryview->adb,
2992 						   MAX_ADB_SIZE_FOR_CACHESHARE);
2993 				nsc->adbsizeadjusted = ISC_TRUE;
2994 			}
2995 		}
2996 	}
2997 	dns_adb_setadbsize(view->adb, max_adb_size);
2998 
2999 	/*
3000 	 * Set resolver's lame-ttl.
3001 	 */
3002 	obj = NULL;
3003 	result = ns_config_get(maps, "lame-ttl", &obj);
3004 	INSIST(result == ISC_R_SUCCESS);
3005 	lame_ttl = cfg_obj_asuint32(obj);
3006 	if (lame_ttl > 1800)
3007 		lame_ttl = 1800;
3008 	dns_resolver_setlamettl(view->resolver, lame_ttl);
3009 
3010 	/*
3011 	 * Set the resolver's query timeout.
3012 	 */
3013 	obj = NULL;
3014 	result = ns_config_get(maps, "resolver-query-timeout", &obj);
3015 	INSIST(result == ISC_R_SUCCESS);
3016 	query_timeout = cfg_obj_asuint32(obj);
3017 	dns_resolver_settimeout(view->resolver, query_timeout);
3018 
3019 	/* Specify whether to use 0-TTL for negative response for SOA query */
3020 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
3021 
3022 	/*
3023 	 * Set the resolver's EDNS UDP size.
3024 	 */
3025 	obj = NULL;
3026 	result = ns_config_get(maps, "edns-udp-size", &obj);
3027 	INSIST(result == ISC_R_SUCCESS);
3028 	udpsize = cfg_obj_asuint32(obj);
3029 	if (udpsize < 512)
3030 		udpsize = 512;
3031 	if (udpsize > 4096)
3032 		udpsize = 4096;
3033 	dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
3034 
3035 	/*
3036 	 * Set the maximum UDP response size.
3037 	 */
3038 	obj = NULL;
3039 	result = ns_config_get(maps, "max-udp-size", &obj);
3040 	INSIST(result == ISC_R_SUCCESS);
3041 	udpsize = cfg_obj_asuint32(obj);
3042 	if (udpsize < 512)
3043 		udpsize = 512;
3044 	if (udpsize > 4096)
3045 		udpsize = 4096;
3046 	view->maxudp = udpsize;
3047 
3048 #ifdef ISC_PLATFORM_USESIT
3049 	/*
3050 	 * Set the maximum UDP when a SIT is not provided.
3051 	 */
3052 	obj = NULL;
3053 	result = ns_config_get(maps, "nosit-udp-size", &obj);
3054 	INSIST(result == ISC_R_SUCCESS);
3055 	udpsize = cfg_obj_asuint32(obj);
3056 	if (udpsize < 128)
3057 		udpsize = 128;
3058 	if (udpsize > view->maxudp)
3059 		udpsize = view->maxudp;
3060 	view->situdp = udpsize;
3061 #endif
3062 
3063 	/*
3064 	 * Set the maximum rsa exponent bits.
3065 	 */
3066 	obj = NULL;
3067 	result = ns_config_get(maps, "max-rsa-exponent-size", &obj);
3068 	INSIST(result == ISC_R_SUCCESS);
3069 	maxbits = cfg_obj_asuint32(obj);
3070 	if (maxbits != 0 && maxbits < 35)
3071 		maxbits = 35;
3072 	if (maxbits > 4096)
3073 		maxbits = 4096;
3074 	view->maxbits = maxbits;
3075 
3076 	/*
3077 	 * Set supported DNSSEC algorithms.
3078 	 */
3079 	dns_resolver_reset_algorithms(view->resolver);
3080 	disabled = NULL;
3081 	(void)ns_config_get(maps, "disable-algorithms", &disabled);
3082 	if (disabled != NULL) {
3083 		for (element = cfg_list_first(disabled);
3084 		     element != NULL;
3085 		     element = cfg_list_next(element))
3086 			CHECK(disable_algorithms(cfg_listelt_value(element),
3087 						 view->resolver));
3088 	}
3089 
3090 	/*
3091 	 * Set supported DS/DLV digest types.
3092 	 */
3093 	dns_resolver_reset_ds_digests(view->resolver);
3094 	disabled = NULL;
3095 	(void)ns_config_get(maps, "disable-ds-digests", &disabled);
3096 	if (disabled != NULL) {
3097 		for (element = cfg_list_first(disabled);
3098 		     element != NULL;
3099 		     element = cfg_list_next(element))
3100 			CHECK(disable_ds_digests(cfg_listelt_value(element),
3101 						 view->resolver));
3102 	}
3103 
3104 	/*
3105 	 * A global or view "forwarders" option, if present,
3106 	 * creates an entry for "." in the forwarding table.
3107 	 */
3108 	forwardtype = NULL;
3109 	forwarders = NULL;
3110 	(void)ns_config_get(maps, "forward", &forwardtype);
3111 	(void)ns_config_get(maps, "forwarders", &forwarders);
3112 	if (forwarders != NULL)
3113 		CHECK(configure_forward(config, view, dns_rootname,
3114 					forwarders, forwardtype));
3115 
3116 	/*
3117 	 * Dual Stack Servers.
3118 	 */
3119 	alternates = NULL;
3120 	(void)ns_config_get(maps, "dual-stack-servers", &alternates);
3121 	if (alternates != NULL)
3122 		CHECK(configure_alternates(config, view, alternates));
3123 
3124 	/*
3125 	 * We have default hints for class IN if we need them.
3126 	 */
3127 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
3128 		dns_view_sethints(view, ns_g_server->in_roothints);
3129 
3130 	/*
3131 	 * If we still have no hints, this is a non-IN view with no
3132 	 * "hints zone" configured.  Issue a warning, except if this
3133 	 * is a root server.  Root servers never need to consult
3134 	 * their hints, so it's no point requiring users to configure
3135 	 * them.
3136 	 */
3137 	if (view->hints == NULL) {
3138 		dns_zone_t *rootzone = NULL;
3139 		(void)dns_view_findzone(view, dns_rootname, &rootzone);
3140 		if (rootzone != NULL) {
3141 			dns_zone_detach(&rootzone);
3142 			need_hints = ISC_FALSE;
3143 		}
3144 		if (need_hints)
3145 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3146 				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3147 				      "no root hints for view '%s'",
3148 				      view->name);
3149 	}
3150 
3151 	/*
3152 	 * Configure the view's TSIG keys.
3153 	 */
3154 	CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
3155 	if (ns_g_server->sessionkey != NULL) {
3156 		CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname,
3157 					  ns_g_server->sessionkey));
3158 	}
3159 	dns_view_setkeyring(view, ring);
3160 	dns_tsigkeyring_detach(&ring);
3161 
3162 	/*
3163 	 * See if we can re-use a dynamic key ring.
3164 	 */
3165 	result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
3166 				   view->rdclass, &pview);
3167 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3168 		goto cleanup;
3169 	if (pview != NULL) {
3170 		dns_view_getdynamickeyring(pview, &ring);
3171 		if (ring != NULL)
3172 			dns_view_setdynamickeyring(view, ring);
3173 		dns_tsigkeyring_detach(&ring);
3174 		dns_view_detach(&pview);
3175 	} else
3176 		dns_view_restorekeyring(view);
3177 
3178 	/*
3179 	 * Configure the view's peer list.
3180 	 */
3181 	{
3182 		const cfg_obj_t *peers = NULL;
3183 		dns_peerlist_t *newpeers = NULL;
3184 
3185 		(void)ns_config_get(cfgmaps, "server", &peers);
3186 		CHECK(dns_peerlist_new(mctx, &newpeers));
3187 		for (element = cfg_list_first(peers);
3188 		     element != NULL;
3189 		     element = cfg_list_next(element))
3190 		{
3191 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
3192 			dns_peer_t *peer;
3193 
3194 			CHECK(configure_peer(cpeer, mctx, &peer));
3195 			dns_peerlist_addpeer(newpeers, peer);
3196 			dns_peer_detach(&peer);
3197 		}
3198 		dns_peerlist_detach(&view->peers);
3199 		view->peers = newpeers; /* Transfer ownership. */
3200 	}
3201 
3202 	/*
3203 	 *	Configure the views rrset-order.
3204 	 */
3205 	{
3206 		const cfg_obj_t *rrsetorder = NULL;
3207 
3208 		(void)ns_config_get(maps, "rrset-order", &rrsetorder);
3209 		CHECK(dns_order_create(mctx, &order));
3210 		for (element = cfg_list_first(rrsetorder);
3211 		     element != NULL;
3212 		     element = cfg_list_next(element))
3213 		{
3214 			const cfg_obj_t *ent = cfg_listelt_value(element);
3215 
3216 			CHECK(configure_order(order, ent));
3217 		}
3218 		if (view->order != NULL)
3219 			dns_order_detach(&view->order);
3220 		dns_order_attach(order, &view->order);
3221 		dns_order_detach(&order);
3222 	}
3223 	/*
3224 	 * Copy the aclenv object.
3225 	 */
3226 	dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
3227 
3228 	/*
3229 	 * Configure the "match-clients" and "match-destinations" ACL.
3230 	 */
3231 	CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx,
3232 				 ns_g_mctx, &view->matchclients));
3233 	CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL,
3234 				 actx, ns_g_mctx, &view->matchdestinations));
3235 
3236 	/*
3237 	 * Configure the "match-recursive-only" option.
3238 	 */
3239 	obj = NULL;
3240 	(void)ns_config_get(maps, "match-recursive-only", &obj);
3241 	if (obj != NULL && cfg_obj_asboolean(obj))
3242 		view->matchrecursiveonly = ISC_TRUE;
3243 	else
3244 		view->matchrecursiveonly = ISC_FALSE;
3245 
3246 	/*
3247 	 * Configure other configurable data.
3248 	 */
3249 	obj = NULL;
3250 	result = ns_config_get(maps, "recursion", &obj);
3251 	INSIST(result == ISC_R_SUCCESS);
3252 	view->recursion = cfg_obj_asboolean(obj);
3253 
3254 	obj = NULL;
3255 	result = ns_config_get(maps, "auth-nxdomain", &obj);
3256 	INSIST(result == ISC_R_SUCCESS);
3257 	view->auth_nxdomain = cfg_obj_asboolean(obj);
3258 
3259 	obj = NULL;
3260 	result = ns_config_get(maps, "minimal-responses", &obj);
3261 	INSIST(result == ISC_R_SUCCESS);
3262 	view->minimalresponses = cfg_obj_asboolean(obj);
3263 
3264 	obj = NULL;
3265 	result = ns_config_get(maps, "transfer-format", &obj);
3266 	INSIST(result == ISC_R_SUCCESS);
3267 	str = cfg_obj_asstring(obj);
3268 	if (strcasecmp(str, "many-answers") == 0)
3269 		view->transfer_format = dns_many_answers;
3270 	else if (strcasecmp(str, "one-answer") == 0)
3271 		view->transfer_format = dns_one_answer;
3272 	else
3273 		INSIST(0);
3274 
3275 	/*
3276 	 * Set sources where additional data and CNAME/DNAME
3277 	 * targets for authoritative answers may be found.
3278 	 */
3279 	obj = NULL;
3280 	result = ns_config_get(maps, "additional-from-auth", &obj);
3281 	INSIST(result == ISC_R_SUCCESS);
3282 	view->additionalfromauth = cfg_obj_asboolean(obj);
3283 	if (view->recursion && ! view->additionalfromauth) {
3284 		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
3285 			    "'additional-from-auth no' is only supported "
3286 			    "with 'recursion no'");
3287 		view->additionalfromauth = ISC_TRUE;
3288 	}
3289 
3290 	obj = NULL;
3291 	result = ns_config_get(maps, "additional-from-cache", &obj);
3292 	INSIST(result == ISC_R_SUCCESS);
3293 	view->additionalfromcache = cfg_obj_asboolean(obj);
3294 	if (view->recursion && ! view->additionalfromcache) {
3295 		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
3296 			    "'additional-from-cache no' is only supported "
3297 			    "with 'recursion no'");
3298 		view->additionalfromcache = ISC_TRUE;
3299 	}
3300 
3301 	/*
3302 	 * Set "allow-query-cache", "allow-query-cache-on",
3303 	 * "allow-recursion", and "allow-recursion-on" acls if
3304 	 * configured in named.conf.
3305 	 */
3306 	CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL,
3307 				 actx, ns_g_mctx, &view->cacheacl));
3308 	CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL,
3309 				 actx, ns_g_mctx, &view->cacheonacl));
3310 	if (view->cacheonacl == NULL)
3311 		CHECK(configure_view_acl(NULL, ns_g_config,
3312 					 "allow-query-cache-on", NULL, actx,
3313 					 ns_g_mctx, &view->cacheonacl));
3314 	if (strcmp(view->name, "_bind") != 0) {
3315 		CHECK(configure_view_acl(vconfig, config, "allow-recursion",
3316 					 NULL, actx, ns_g_mctx,
3317 					 &view->recursionacl));
3318 		CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
3319 					 NULL, actx, ns_g_mctx,
3320 					 &view->recursiononacl));
3321 	}
3322 
3323 	/*
3324 	 * "allow-query-cache" inherits from "allow-recursion" if set,
3325 	 * otherwise from "allow-query" if set.
3326 	 * "allow-recursion" inherits from "allow-query-cache" if set,
3327 	 * otherwise from "allow-query" if set.
3328 	 */
3329 	if (view->cacheacl == NULL && view->recursionacl != NULL)
3330 		dns_acl_attach(view->recursionacl, &view->cacheacl);
3331 	/*
3332 	 * XXXEACH: This call to configure_view_acl() is redundant.  We
3333 	 * are leaving it as it is because we are making a minimal change
3334 	 * for a patch release.  In the future this should be changed to
3335 	 * dns_acl_attach(view->queryacl, &view->cacheacl).
3336 	 */
3337 	if (view->cacheacl == NULL && view->recursion)
3338 		CHECK(configure_view_acl(vconfig, config, "allow-query", NULL,
3339 					 actx, ns_g_mctx, &view->cacheacl));
3340 	if (view->recursion &&
3341 	    view->recursionacl == NULL && view->cacheacl != NULL)
3342 		dns_acl_attach(view->cacheacl, &view->recursionacl);
3343 
3344 	/*
3345 	 * Set default "allow-recursion", "allow-recursion-on" and
3346 	 * "allow-query-cache" acls.
3347 	 */
3348 	if (view->recursionacl == NULL && view->recursion)
3349 		CHECK(configure_view_acl(NULL, ns_g_config,
3350 					 "allow-recursion", NULL,
3351 					 actx, ns_g_mctx,
3352 					 &view->recursionacl));
3353 	if (view->recursiononacl == NULL && view->recursion)
3354 		CHECK(configure_view_acl(NULL, ns_g_config,
3355 					 "allow-recursion-on", NULL,
3356 					 actx, ns_g_mctx,
3357 					 &view->recursiononacl));
3358 	if (view->cacheacl == NULL) {
3359 		if (view->recursion)
3360 			CHECK(configure_view_acl(NULL, ns_g_config,
3361 						 "allow-query-cache", NULL,
3362 						 actx, ns_g_mctx,
3363 						 &view->cacheacl));
3364 		else
3365 			CHECK(dns_acl_none(mctx, &view->cacheacl));
3366 	}
3367 
3368 	/*
3369 	 * Ignore case when compressing responses to the specified
3370 	 * clients. This causes case not always to be preserved,
3371 	 * and is needed by some broken clients.
3372 	 */
3373 	CHECK(configure_view_acl(vconfig, config, "no-case-compress", NULL,
3374 				 actx, ns_g_mctx, &view->nocasecompress));
3375 
3376 	/*
3377 	 * Filter setting on addresses in the answer section.
3378 	 */
3379 	CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses",
3380 				 "acl", actx, ns_g_mctx, &view->denyansweracl));
3381 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
3382 				       "except-from", ns_g_mctx,
3383 				       &view->answeracl_exclude));
3384 
3385 	/*
3386 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
3387 	 */
3388 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
3389 				       "name", ns_g_mctx,
3390 				       &view->denyanswernames));
3391 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
3392 				       "except-from", ns_g_mctx,
3393 				       &view->answernames_exclude));
3394 
3395 	/*
3396 	 * Configure sortlist, if set
3397 	 */
3398 	CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
3399 				      &view->sortlist));
3400 
3401 	/*
3402 	 * Configure default allow-transfer, allow-notify, allow-update
3403 	 * and allow-update-forwarding ACLs, if set, so they can be
3404 	 * inherited by zones.
3405 	 */
3406 	if (view->notifyacl == NULL)
3407 		CHECK(configure_view_acl(NULL, ns_g_config,
3408 					 "allow-notify", NULL, actx,
3409 					 ns_g_mctx, &view->notifyacl));
3410 	if (view->transferacl == NULL)
3411 		CHECK(configure_view_acl(NULL, ns_g_config,
3412 					 "allow-transfer", NULL, actx,
3413 					 ns_g_mctx, &view->transferacl));
3414 	if (view->updateacl == NULL)
3415 		CHECK(configure_view_acl(NULL, ns_g_config,
3416 					 "allow-update", NULL, actx,
3417 					 ns_g_mctx, &view->updateacl));
3418 	if (view->upfwdacl == NULL)
3419 		CHECK(configure_view_acl(NULL, ns_g_config,
3420 					 "allow-update-forwarding", NULL, actx,
3421 					 ns_g_mctx, &view->upfwdacl));
3422 
3423 	obj = NULL;
3424 	result = ns_config_get(maps, "provide-ixfr", &obj);
3425 	INSIST(result == ISC_R_SUCCESS);
3426 	view->provideixfr = cfg_obj_asboolean(obj);
3427 
3428 	obj = NULL;
3429 	result = ns_config_get(maps, "request-nsid", &obj);
3430 	INSIST(result == ISC_R_SUCCESS);
3431 	view->requestnsid = cfg_obj_asboolean(obj);
3432 
3433 #ifdef ISC_PLATFORM_USESIT
3434 	obj = NULL;
3435 	result = ns_config_get(maps, "request-sit", &obj);
3436 	INSIST(result == ISC_R_SUCCESS);
3437 	view->requestsit = cfg_obj_asboolean(obj);
3438 #endif
3439 
3440 	obj = NULL;
3441 	result = ns_config_get(maps, "max-clients-per-query", &obj);
3442 	INSIST(result == ISC_R_SUCCESS);
3443 	max_clients_per_query = cfg_obj_asuint32(obj);
3444 
3445 	obj = NULL;
3446 	result = ns_config_get(maps, "clients-per-query", &obj);
3447 	INSIST(result == ISC_R_SUCCESS);
3448 	dns_resolver_setclientsperquery(view->resolver,
3449 					cfg_obj_asuint32(obj),
3450 					max_clients_per_query);
3451 
3452 	obj = NULL;
3453 	result = ns_config_get(maps, "max-recursion-depth", &obj);
3454 	INSIST(result == ISC_R_SUCCESS);
3455 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
3456 
3457 	obj = NULL;
3458 	result = ns_config_get(maps, "max-recursion-queries", &obj);
3459 	INSIST(result == ISC_R_SUCCESS);
3460 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
3461 
3462 #ifdef ALLOW_FILTER_AAAA
3463 	obj = NULL;
3464 	result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
3465 	INSIST(result == ISC_R_SUCCESS);
3466 	if (cfg_obj_isboolean(obj)) {
3467 		if (cfg_obj_asboolean(obj))
3468 			view->v4_aaaa = dns_aaaa_filter;
3469 		else
3470 			view->v4_aaaa = dns_aaaa_ok;
3471 	} else {
3472 		const char *v4_aaaastr = cfg_obj_asstring(obj);
3473 		if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
3474 			view->v4_aaaa = dns_aaaa_break_dnssec;
3475 		else
3476 			INSIST(0);
3477 	}
3478 
3479 	obj = NULL;
3480 	result = ns_config_get(maps, "filter-aaaa-on-v6", &obj);
3481 	INSIST(result == ISC_R_SUCCESS);
3482 	if (cfg_obj_isboolean(obj)) {
3483 		if (cfg_obj_asboolean(obj))
3484 			view->v6_aaaa = dns_aaaa_filter;
3485 		else
3486 			view->v6_aaaa = dns_aaaa_ok;
3487 	} else {
3488 		const char *v6_aaaastr = cfg_obj_asstring(obj);
3489 		if (strcasecmp(v6_aaaastr, "break-dnssec") == 0)
3490 			view->v6_aaaa = dns_aaaa_break_dnssec;
3491 		else
3492 			INSIST(0);
3493 	}
3494 
3495 	CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
3496 				 actx, ns_g_mctx, &view->aaaa_acl));
3497 #endif
3498 	obj = NULL;
3499 	result = ns_config_get(maps, "prefetch", &obj);
3500 	if (result == ISC_R_SUCCESS) {
3501 		const cfg_obj_t *trigger, *eligible;
3502 
3503 		trigger = cfg_tuple_get(obj, "trigger");
3504 		view->prefetch_trigger = cfg_obj_asuint32(trigger);
3505 		if (view->prefetch_trigger > 10)
3506 			view->prefetch_trigger = 10;
3507 		eligible = cfg_tuple_get(obj, "eligible");
3508 		if (cfg_obj_isvoid(eligible)) {
3509 			int m;
3510 			for (m = 1; maps[m] != NULL; m++) {
3511 				obj = NULL;
3512 				result = ns_config_get(&maps[m],
3513 						       "prefetch", &obj);
3514 				INSIST(result == ISC_R_SUCCESS);
3515 				eligible = cfg_tuple_get(obj, "eligible");
3516 				if (cfg_obj_isuint32(eligible))
3517 					break;
3518 			}
3519 			INSIST(cfg_obj_isuint32(eligible));
3520 		}
3521 		view->prefetch_eligible = cfg_obj_asuint32(eligible);
3522 		if (view->prefetch_eligible < view->prefetch_trigger + 6)
3523 			view->prefetch_eligible = view->prefetch_trigger + 6;
3524 	}
3525 
3526 	obj = NULL;
3527 	result = ns_config_get(maps, "dnssec-enable", &obj);
3528 	INSIST(result == ISC_R_SUCCESS);
3529 	view->enablednssec = cfg_obj_asboolean(obj);
3530 
3531 	obj = NULL;
3532 	result = ns_config_get(optionmaps, "dnssec-lookaside", &obj);
3533 	if (result == ISC_R_SUCCESS) {
3534 		/* If set to "auto", use the version from the defaults */
3535 		const cfg_obj_t *dlvobj;
3536 		const char *dom;
3537 		dlvobj = cfg_listelt_value(cfg_list_first(obj));
3538 		dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
3539 		if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
3540 			/* If "no", skip; if "auto", use global default */
3541 			if (!strcasecmp(dom, "no"))
3542 				result = ISC_R_NOTFOUND;
3543 			else if (!strcasecmp(dom, "auto")) {
3544 				auto_dlv = ISC_TRUE;
3545 				obj = NULL;
3546 				result = cfg_map_get(ns_g_defaults,
3547 						     "dnssec-lookaside", &obj);
3548 			}
3549 		}
3550 	}
3551 
3552 	if (result == ISC_R_SUCCESS) {
3553 		for (element = cfg_list_first(obj);
3554 		     element != NULL;
3555 		     element = cfg_list_next(element))
3556 		{
3557 			dns_name_t *dlv;
3558 
3559 			obj = cfg_listelt_value(element);
3560 			obj = cfg_tuple_get(obj, "trust-anchor");
3561 			dlv = dns_fixedname_name(&view->dlv_fixed);
3562 			CHECK(dns_name_fromstring(dlv, cfg_obj_asstring(obj),
3563 						  DNS_NAME_DOWNCASE, NULL));
3564 			view->dlv = dns_fixedname_name(&view->dlv_fixed);
3565 		}
3566 	} else
3567 		view->dlv = NULL;
3568 
3569 	/*
3570 	 * For now, there is only one kind of trusted keys, the
3571 	 * "security roots".
3572 	 */
3573 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
3574 					auto_dlv, auto_root, mctx));
3575 	dns_resolver_resetmustbesecure(view->resolver);
3576 	obj = NULL;
3577 	result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
3578 	if (result == ISC_R_SUCCESS)
3579 		CHECK(mustbesecure(obj, view->resolver));
3580 
3581 	obj = NULL;
3582 	result = ns_config_get(maps, "preferred-glue", &obj);
3583 	if (result == ISC_R_SUCCESS) {
3584 		str = cfg_obj_asstring(obj);
3585 		if (strcasecmp(str, "a") == 0)
3586 			view->preferred_glue = dns_rdatatype_a;
3587 		else if (strcasecmp(str, "aaaa") == 0)
3588 			view->preferred_glue = dns_rdatatype_aaaa;
3589 		else
3590 			view->preferred_glue = 0;
3591 	} else
3592 		view->preferred_glue = 0;
3593 
3594 	obj = NULL;
3595 	result = ns_config_get(maps, "root-delegation-only", &obj);
3596 	if (result == ISC_R_SUCCESS) {
3597 		dns_fixedname_t fixed;
3598 		dns_name_t *name;
3599 		const cfg_obj_t *exclude;
3600 
3601 		dns_view_setrootdelonly(view, ISC_TRUE);
3602 
3603 		dns_fixedname_init(&fixed);
3604 		name = dns_fixedname_name(&fixed);
3605 		for (element = cfg_list_first(obj);
3606 		     element != NULL;
3607 		     element = cfg_list_next(element)) {
3608 			exclude = cfg_listelt_value(element);
3609 			CHECK(dns_name_fromstring(name,
3610 						  cfg_obj_asstring(exclude),
3611 						  0, NULL));
3612 			CHECK(dns_view_excludedelegationonly(view, name));
3613 		}
3614 	} else
3615 		dns_view_setrootdelonly(view, ISC_FALSE);
3616 
3617 	/*
3618 	 * Setup automatic empty zones.  If recursion is off then
3619 	 * they are disabled by default.
3620 	 */
3621 	obj = NULL;
3622 	(void)ns_config_get(maps, "empty-zones-enable", &obj);
3623 	(void)ns_config_get(maps, "disable-empty-zone", &disablelist);
3624 	if (obj == NULL && disablelist == NULL &&
3625 	    view->rdclass == dns_rdataclass_in) {
3626 		empty_zones_enable = view->recursion;
3627 	} else if (view->rdclass == dns_rdataclass_in) {
3628 		if (obj != NULL)
3629 			empty_zones_enable = cfg_obj_asboolean(obj);
3630 		else
3631 			empty_zones_enable = view->recursion;
3632 	} else {
3633 		empty_zones_enable = ISC_FALSE;
3634 	}
3635 	if (empty_zones_enable && !lwresd_g_useresolvconf) {
3636 		const char *empty;
3637 		int empty_zone = 0;
3638 		dns_fixedname_t fixed;
3639 		dns_name_t *name;
3640 		isc_buffer_t buffer;
3641 		char server[DNS_NAME_FORMATSIZE + 1];
3642 		char contact[DNS_NAME_FORMATSIZE + 1];
3643 		const char *empty_dbtype[4] =
3644 				    { "_builtin", "empty", NULL, NULL };
3645 		int empty_dbtypec = 4;
3646 		dns_zonestat_level_t statlevel;
3647 
3648 		dns_fixedname_init(&fixed);
3649 		name = dns_fixedname_name(&fixed);
3650 
3651 		obj = NULL;
3652 		result = ns_config_get(maps, "empty-server", &obj);
3653 		if (result == ISC_R_SUCCESS) {
3654 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
3655 						  0, NULL));
3656 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
3657 			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
3658 			server[isc_buffer_usedlength(&buffer)] = 0;
3659 			empty_dbtype[2] = server;
3660 		} else
3661 			empty_dbtype[2] = "@";
3662 
3663 		obj = NULL;
3664 		result = ns_config_get(maps, "empty-contact", &obj);
3665 		if (result == ISC_R_SUCCESS) {
3666 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
3667 						 0, NULL));
3668 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
3669 			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
3670 			contact[isc_buffer_usedlength(&buffer)] = 0;
3671 			empty_dbtype[3] = contact;
3672 		} else
3673 			empty_dbtype[3] = ".";
3674 
3675 		obj = NULL;
3676 		result = ns_config_get(maps, "zone-statistics", &obj);
3677 		INSIST(result == ISC_R_SUCCESS);
3678 		if (cfg_obj_isboolean(obj)) {
3679 			if (cfg_obj_asboolean(obj))
3680 				statlevel = dns_zonestat_full;
3681 			else
3682 				statlevel = dns_zonestat_none;
3683 		} else {
3684 			const char *levelstr = cfg_obj_asstring(obj);
3685 			if (strcasecmp(levelstr, "full") == 0)
3686 				statlevel = dns_zonestat_full;
3687 			else if (strcasecmp(levelstr, "terse") == 0)
3688 				statlevel = dns_zonestat_terse;
3689 			else if (strcasecmp(levelstr, "none") == 0)
3690 				statlevel = dns_zonestat_none;
3691 			else
3692 				INSIST(0);
3693 		}
3694 
3695 		for (empty = empty_zones[empty_zone];
3696 		     empty != NULL;
3697 		     empty = empty_zones[++empty_zone])
3698 		{
3699 			dns_forwarders_t *dnsforwarders = NULL;
3700 
3701 			/*
3702 			 * Look for zone on drop list.
3703 			 */
3704 			CHECK(dns_name_fromstring(name, empty, 0, NULL));
3705 			if (disablelist != NULL &&
3706 			    on_disable_list(disablelist, name))
3707 				continue;
3708 
3709 			/*
3710 			 * This zone already exists.
3711 			 */
3712 			(void)dns_view_findzone(view, name, &zone);
3713 			if (zone != NULL) {
3714 				dns_zone_detach(&zone);
3715 				continue;
3716 			}
3717 
3718 			/*
3719 			 * If we would forward this name don't add a
3720 			 * empty zone for it.
3721 			 */
3722 			result = dns_fwdtable_find(view->fwdtable, name,
3723 						   &dnsforwarders);
3724 			if (result == ISC_R_SUCCESS &&
3725 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
3726 				continue;
3727 
3728 			/*
3729 			 * See if we can re-use a existing zone.
3730 			 */
3731 			result = dns_viewlist_find(&ns_g_server->viewlist,
3732 						   view->name, view->rdclass,
3733 						   &pview);
3734 			if (result != ISC_R_NOTFOUND &&
3735 			    result != ISC_R_SUCCESS)
3736 				goto cleanup;
3737 
3738 			if (pview != NULL) {
3739 				(void)dns_view_findzone(pview, name, &zone);
3740 				dns_view_detach(&pview);
3741 			}
3742 
3743 			CHECK(create_empty_zone(zone, name, view, zonelist,
3744 						empty_dbtype, empty_dbtypec,
3745 						statlevel));
3746 			if (zone != NULL)
3747 				dns_zone_detach(&zone);
3748 		}
3749 	}
3750 
3751 	obj = NULL;
3752 	result = ns_config_get(maps, "rate-limit", &obj);
3753 	if (result == ISC_R_SUCCESS) {
3754 		result = configure_rrl(view, config, obj);
3755 		if (result != ISC_R_SUCCESS)
3756 			goto cleanup;
3757 	}
3758 
3759 	result = ISC_R_SUCCESS;
3760 
3761  cleanup:
3762 	if (clients != NULL)
3763 		dns_acl_detach(&clients);
3764 	if (mapped != NULL)
3765 		dns_acl_detach(&mapped);
3766 	if (excluded != NULL)
3767 		dns_acl_detach(&excluded);
3768 	if (ring != NULL)
3769 		dns_tsigkeyring_detach(&ring);
3770 	if (zone != NULL)
3771 		dns_zone_detach(&zone);
3772 	if (dispatch4 != NULL)
3773 		dns_dispatch_detach(&dispatch4);
3774 	if (dispatch6 != NULL)
3775 		dns_dispatch_detach(&dispatch6);
3776 	if (resstats != NULL)
3777 		isc_stats_detach(&resstats);
3778 	if (resquerystats != NULL)
3779 		dns_stats_detach(&resquerystats);
3780 	if (order != NULL)
3781 		dns_order_detach(&order);
3782 	if (cmctx != NULL)
3783 		isc_mem_detach(&cmctx);
3784 	if (hmctx != NULL)
3785 		isc_mem_detach(&hmctx);
3786 
3787 	if (cache != NULL)
3788 		dns_cache_detach(&cache);
3789 
3790 	return (result);
3791 }
3792 
3793 static isc_result_t
3794 configure_hints(dns_view_t *view, const char *filename) {
3795 	isc_result_t result;
3796 	dns_db_t *db;
3797 
3798 	db = NULL;
3799 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
3800 	if (result == ISC_R_SUCCESS) {
3801 		dns_view_sethints(view, db);
3802 		dns_db_detach(&db);
3803 	}
3804 
3805 	return (result);
3806 }
3807 
3808 static isc_result_t
3809 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
3810 		     const cfg_obj_t *alternates)
3811 {
3812 	const cfg_obj_t *portobj;
3813 	const cfg_obj_t *addresses;
3814 	const cfg_listelt_t *element;
3815 	isc_result_t result = ISC_R_SUCCESS;
3816 	in_port_t port;
3817 
3818 	/*
3819 	 * Determine which port to send requests to.
3820 	 */
3821 	if (ns_g_lwresdonly && ns_g_port != 0)
3822 		port = ns_g_port;
3823 	else
3824 		CHECKM(ns_config_getport(config, &port), "port");
3825 
3826 	if (alternates != NULL) {
3827 		portobj = cfg_tuple_get(alternates, "port");
3828 		if (cfg_obj_isuint32(portobj)) {
3829 			isc_uint32_t val = cfg_obj_asuint32(portobj);
3830 			if (val > ISC_UINT16_MAX) {
3831 				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3832 					    "port '%u' out of range", val);
3833 				return (ISC_R_RANGE);
3834 			}
3835 			port = (in_port_t) val;
3836 		}
3837 	}
3838 
3839 	addresses = NULL;
3840 	if (alternates != NULL)
3841 		addresses = cfg_tuple_get(alternates, "addresses");
3842 
3843 	for (element = cfg_list_first(addresses);
3844 	     element != NULL;
3845 	     element = cfg_list_next(element))
3846 	{
3847 		const cfg_obj_t *alternate = cfg_listelt_value(element);
3848 		isc_sockaddr_t sa;
3849 
3850 		if (!cfg_obj_issockaddr(alternate)) {
3851 			dns_fixedname_t fixed;
3852 			dns_name_t *name;
3853 			const char *str = cfg_obj_asstring(cfg_tuple_get(
3854 							   alternate, "name"));
3855 			isc_buffer_t buffer;
3856 			in_port_t myport = port;
3857 
3858 			isc_buffer_constinit(&buffer, str, strlen(str));
3859 			isc_buffer_add(&buffer, strlen(str));
3860 			dns_fixedname_init(&fixed);
3861 			name = dns_fixedname_name(&fixed);
3862 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3863 						NULL));
3864 
3865 			portobj = cfg_tuple_get(alternate, "port");
3866 			if (cfg_obj_isuint32(portobj)) {
3867 				isc_uint32_t val = cfg_obj_asuint32(portobj);
3868 				if (val > ISC_UINT16_MAX) {
3869 					cfg_obj_log(portobj, ns_g_lctx,
3870 						    ISC_LOG_ERROR,
3871 						    "port '%u' out of range",
3872 						     val);
3873 					return (ISC_R_RANGE);
3874 				}
3875 				myport = (in_port_t) val;
3876 			}
3877 			CHECK(dns_resolver_addalternate(view->resolver, NULL,
3878 							name, myport));
3879 			continue;
3880 		}
3881 
3882 		sa = *cfg_obj_assockaddr(alternate);
3883 		if (isc_sockaddr_getport(&sa) == 0)
3884 			isc_sockaddr_setport(&sa, port);
3885 		CHECK(dns_resolver_addalternate(view->resolver, &sa,
3886 						NULL, 0));
3887 	}
3888 
3889  cleanup:
3890 	return (result);
3891 }
3892 
3893 static isc_result_t
3894 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
3895 		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
3896 {
3897 	const cfg_obj_t *portobj, *dscpobj;
3898 	const cfg_obj_t *faddresses;
3899 	const cfg_listelt_t *element;
3900 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
3901 	dns_forwarderlist_t fwdlist;
3902 	dns_forwarder_t *fwd;
3903 	isc_result_t result;
3904 	in_port_t port;
3905 	isc_dscp_t dscp = -1;
3906 
3907 	ISC_LIST_INIT(fwdlist);
3908 
3909 	/*
3910 	 * Determine which port to send forwarded requests to.
3911 	 */
3912 	if (ns_g_lwresdonly && ns_g_port != 0)
3913 		port = ns_g_port;
3914 	else
3915 		CHECKM(ns_config_getport(config, &port), "port");
3916 
3917 	if (forwarders != NULL) {
3918 		portobj = cfg_tuple_get(forwarders, "port");
3919 		if (cfg_obj_isuint32(portobj)) {
3920 			isc_uint32_t val = cfg_obj_asuint32(portobj);
3921 			if (val > ISC_UINT16_MAX) {
3922 				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3923 					    "port '%u' out of range", val);
3924 				return (ISC_R_RANGE);
3925 			}
3926 			port = (in_port_t) val;
3927 		}
3928 	}
3929 
3930 	/*
3931 	 * DSCP value for forwarded requests.
3932 	 */
3933 	dscp = ns_g_dscp;
3934 	if (forwarders != NULL) {
3935 		dscpobj = cfg_tuple_get(forwarders, "dscp");
3936 		if (cfg_obj_isuint32(dscpobj)) {
3937 			if (cfg_obj_asuint32(dscpobj) > 63) {
3938 				cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
3939 					    "dscp value '%u' is out of range",
3940 					    cfg_obj_asuint32(dscpobj));
3941 				return (ISC_R_RANGE);
3942 			}
3943 			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
3944 		}
3945 	}
3946 
3947 	faddresses = NULL;
3948 	if (forwarders != NULL)
3949 		faddresses = cfg_tuple_get(forwarders, "addresses");
3950 
3951 	for (element = cfg_list_first(faddresses);
3952 	     element != NULL;
3953 	     element = cfg_list_next(element))
3954 	{
3955 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
3956 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
3957 		if (fwd == NULL) {
3958 			result = ISC_R_NOMEMORY;
3959 			goto cleanup;
3960 		}
3961 		fwd->addr = *cfg_obj_assockaddr(forwarder);
3962 		if (isc_sockaddr_getport(&fwd->addr) == 0)
3963 			isc_sockaddr_setport(&fwd->addr, port);
3964 		fwd->dscp = cfg_obj_getdscp(forwarder);
3965 		if (fwd->dscp == -1)
3966 			fwd->dscp = dscp;
3967 		ISC_LINK_INIT(fwd, link);
3968 		ISC_LIST_APPEND(fwdlist, fwd, link);
3969 	}
3970 
3971 	if (ISC_LIST_EMPTY(fwdlist)) {
3972 		if (forwardtype != NULL)
3973 			cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3974 				    "no forwarders seen; disabling "
3975 				    "forwarding");
3976 		fwdpolicy = dns_fwdpolicy_none;
3977 	} else {
3978 		if (forwardtype == NULL)
3979 			fwdpolicy = dns_fwdpolicy_first;
3980 		else {
3981 			const char *forwardstr = cfg_obj_asstring(forwardtype);
3982 			if (strcasecmp(forwardstr, "first") == 0)
3983 				fwdpolicy = dns_fwdpolicy_first;
3984 			else if (strcasecmp(forwardstr, "only") == 0)
3985 				fwdpolicy = dns_fwdpolicy_only;
3986 			else
3987 				INSIST(0);
3988 		}
3989 	}
3990 
3991 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
3992 				     fwdpolicy);
3993 	if (result != ISC_R_SUCCESS) {
3994 		char namebuf[DNS_NAME_FORMATSIZE];
3995 		dns_name_format(origin, namebuf, sizeof(namebuf));
3996 		cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3997 			    "could not set up forwarding for domain '%s': %s",
3998 			    namebuf, isc_result_totext(result));
3999 		goto cleanup;
4000 	}
4001 
4002 	result = ISC_R_SUCCESS;
4003 
4004  cleanup:
4005 
4006 	while (!ISC_LIST_EMPTY(fwdlist)) {
4007 		fwd = ISC_LIST_HEAD(fwdlist);
4008 		ISC_LIST_UNLINK(fwdlist, fwd, link);
4009 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
4010 	}
4011 
4012 	return (result);
4013 }
4014 
4015 static isc_result_t
4016 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
4017 	     dns_rdataclass_t *classp)
4018 {
4019 	isc_result_t result = ISC_R_SUCCESS;
4020 	const char *viewname;
4021 	dns_rdataclass_t viewclass;
4022 
4023 	REQUIRE(namep != NULL && *namep == NULL);
4024 	REQUIRE(classp != NULL);
4025 
4026 	if (vconfig != NULL) {
4027 		const cfg_obj_t *classobj = NULL;
4028 
4029 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
4030 		classobj = cfg_tuple_get(vconfig, "class");
4031 		result = ns_config_getclass(classobj, dns_rdataclass_in,
4032 					    &viewclass);
4033 	} else {
4034 		viewname = "_default";
4035 		viewclass = dns_rdataclass_in;
4036 	}
4037 
4038 	*namep = viewname;
4039 	*classp = viewclass;
4040 
4041 	return (result);
4042 }
4043 
4044 /*
4045  * Find a view based on its configuration info and attach to it.
4046  *
4047  * If 'vconfig' is NULL, attach to the default view.
4048  */
4049 static isc_result_t
4050 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
4051 	  dns_view_t **viewp)
4052 {
4053 	isc_result_t result;
4054 	const char *viewname = NULL;
4055 	dns_rdataclass_t viewclass;
4056 	dns_view_t *view = NULL;
4057 
4058 	result = get_viewinfo(vconfig, &viewname, &viewclass);
4059 	if (result != ISC_R_SUCCESS)
4060 		return (result);
4061 
4062 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
4063 	if (result != ISC_R_SUCCESS)
4064 		return (result);
4065 
4066 	*viewp = view;
4067 	return (ISC_R_SUCCESS);
4068 }
4069 
4070 /*
4071  * Create a new view and add it to the list.
4072  *
4073  * If 'vconfig' is NULL, create the default view.
4074  *
4075  * The view created is attached to '*viewp'.
4076  */
4077 static isc_result_t
4078 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
4079 	    dns_view_t **viewp)
4080 {
4081 	isc_result_t result;
4082 	const char *viewname = NULL;
4083 	dns_rdataclass_t viewclass;
4084 	dns_view_t *view = NULL;
4085 
4086 	result = get_viewinfo(vconfig, &viewname, &viewclass);
4087 	if (result != ISC_R_SUCCESS)
4088 		return (result);
4089 
4090 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
4091 	if (result == ISC_R_SUCCESS)
4092 		return (ISC_R_EXISTS);
4093 	if (result != ISC_R_NOTFOUND)
4094 		return (result);
4095 	INSIST(view == NULL);
4096 
4097 	result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
4098 	if (result != ISC_R_SUCCESS)
4099 		return (result);
4100 
4101 	result = isc_entropy_getdata(ns_g_entropy, view->secret,
4102 				     sizeof(view->secret), NULL, 0);
4103 	if (result != ISC_R_SUCCESS) {
4104 		dns_view_detach(&view);
4105 		return (result);
4106 	}
4107 
4108 #ifdef HAVE_GEOIP
4109 	view->aclenv.geoip = ns_g_geoip;
4110 #endif
4111 
4112 	ISC_LIST_APPEND(*viewlist, view, link);
4113 	dns_view_attach(view, viewp);
4114 	return (ISC_R_SUCCESS);
4115 }
4116 
4117 /*
4118  * Configure or reconfigure a zone.
4119  */
4120 static isc_result_t
4121 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
4122 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
4123 	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
4124 	       isc_boolean_t added, isc_boolean_t old_rpz_ok)
4125 {
4126 	dns_view_t *pview = NULL;	/* Production view */
4127 	dns_zone_t *zone = NULL;	/* New or reused zone */
4128 	dns_zone_t *raw = NULL;		/* New or reused raw zone */
4129 	dns_zone_t *dupzone = NULL;
4130 	const cfg_obj_t *options = NULL;
4131 	const cfg_obj_t *zoptions = NULL;
4132 	const cfg_obj_t *typeobj = NULL;
4133 	const cfg_obj_t *forwarders = NULL;
4134 	const cfg_obj_t *forwardtype = NULL;
4135 	const cfg_obj_t *only = NULL;
4136 	const cfg_obj_t *signing = NULL;
4137 	const cfg_obj_t *viewobj = NULL;
4138 	isc_result_t result;
4139 	isc_result_t tresult;
4140 	isc_buffer_t buffer;
4141 	dns_fixedname_t fixorigin;
4142 	dns_name_t *origin;
4143 	const char *zname;
4144 	dns_rdataclass_t zclass;
4145 	const char *ztypestr;
4146 	dns_rpz_num_t rpz_num;
4147 
4148 	options = NULL;
4149 	(void)cfg_map_get(config, "options", &options);
4150 
4151 	zoptions = cfg_tuple_get(zconfig, "options");
4152 
4153 	/*
4154 	 * Get the zone origin as a dns_name_t.
4155 	 */
4156 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
4157 	isc_buffer_constinit(&buffer, zname, strlen(zname));
4158 	isc_buffer_add(&buffer, strlen(zname));
4159 	dns_fixedname_init(&fixorigin);
4160 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
4161 				&buffer, dns_rootname, 0, NULL));
4162 	origin = dns_fixedname_name(&fixorigin);
4163 
4164 	CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
4165 				 view->rdclass, &zclass));
4166 	if (zclass != view->rdclass) {
4167 		const char *vname = NULL;
4168 		if (vconfig != NULL)
4169 			vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
4170 							       "name"));
4171 		else
4172 			vname = "<default view>";
4173 
4174 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4175 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4176 			      "zone '%s': wrong class for view '%s'",
4177 			      zname, vname);
4178 		result = ISC_R_FAILURE;
4179 		goto cleanup;
4180 	}
4181 
4182 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
4183 	if (viewobj != NULL) {
4184 		const char *inview = cfg_obj_asstring(viewobj);
4185 		dns_view_t *otherview = NULL;
4186 
4187 		if (viewlist == NULL) {
4188 			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4189 				    "'in-view' option is not permitted in "
4190 				    "dynamically added zones");
4191 			result = ISC_R_FAILURE;
4192 			goto cleanup;
4193 		}
4194 
4195 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
4196 					   &otherview);
4197 		if (result != ISC_R_SUCCESS) {
4198 			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4199 				    "view '%s' is not yet defined.", inview);
4200 			result = ISC_R_FAILURE;
4201 			goto cleanup;
4202 		}
4203 
4204 		result = dns_view_findzone(otherview, origin, &zone);
4205 		dns_view_detach(&otherview);
4206 		if (result != ISC_R_SUCCESS) {
4207 			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4208 				    "zone '%s' not defined in view '%s'",
4209 				    zname, inview);
4210 			result = ISC_R_FAILURE;
4211 			goto cleanup;
4212 		}
4213 
4214 		CHECK(dns_view_addzone(view, zone));
4215 		dns_zone_detach(&zone);
4216 
4217 		/*
4218 		 * If the zone contains a 'forwarders' statement, configure
4219 		 * selective forwarding.  Note: this is not inherited from the
4220 		 * other view.
4221 		 */
4222 		forwarders = NULL;
4223 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
4224 		if (result == ISC_R_SUCCESS) {
4225 			forwardtype = NULL;
4226 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
4227 			CHECK(configure_forward(config, view, origin,
4228 						forwarders, forwardtype));
4229 		}
4230 		result = ISC_R_SUCCESS;
4231 		goto cleanup;
4232 	}
4233 
4234 	(void)cfg_map_get(zoptions, "type", &typeobj);
4235 	if (typeobj == NULL) {
4236 		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4237 			    "zone '%s' 'type' not specified", zname);
4238 		result = ISC_R_FAILURE;
4239 		goto cleanup;
4240 	}
4241 	ztypestr = cfg_obj_asstring(typeobj);
4242 
4243 	/*
4244 	 * "hints zones" aren't zones.	If we've got one,
4245 	 * configure it and return.
4246 	 */
4247 	if (strcasecmp(ztypestr, "hint") == 0) {
4248 		const cfg_obj_t *fileobj = NULL;
4249 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
4250 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4251 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4252 				      "zone '%s': 'file' not specified",
4253 				      zname);
4254 			result = ISC_R_FAILURE;
4255 			goto cleanup;
4256 		}
4257 		if (dns_name_equal(origin, dns_rootname)) {
4258 			const char *hintsfile = cfg_obj_asstring(fileobj);
4259 
4260 			CHECK(configure_hints(view, hintsfile));
4261 
4262 			/*
4263 			 * Hint zones may also refer to delegation only points.
4264 			 */
4265 			only = NULL;
4266 			tresult = cfg_map_get(zoptions, "delegation-only",
4267 					      &only);
4268 			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
4269 				CHECK(dns_view_adddelegationonly(view, origin));
4270 		} else {
4271 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4272 				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4273 				      "ignoring non-root hint zone '%s'",
4274 				      zname);
4275 			result = ISC_R_SUCCESS;
4276 		}
4277 		/* Skip ordinary zone processing. */
4278 		goto cleanup;
4279 	}
4280 
4281 	/*
4282 	 * "forward zones" aren't zones either.  Translate this syntax into
4283 	 * the appropriate selective forwarding configuration and return.
4284 	 */
4285 	if (strcasecmp(ztypestr, "forward") == 0) {
4286 		forwardtype = NULL;
4287 		forwarders = NULL;
4288 
4289 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
4290 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
4291 		CHECK(configure_forward(config, view, origin, forwarders,
4292 					forwardtype));
4293 
4294 		/*
4295 		 * Forward zones may also set delegation only.
4296 		 */
4297 		only = NULL;
4298 		tresult = cfg_map_get(zoptions, "delegation-only", &only);
4299 		if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
4300 			CHECK(dns_view_adddelegationonly(view, origin));
4301 		goto cleanup;
4302 	}
4303 
4304 	/*
4305 	 * "delegation-only zones" aren't zones either.
4306 	 */
4307 	if (strcasecmp(ztypestr, "delegation-only") == 0) {
4308 		result = dns_view_adddelegationonly(view, origin);
4309 		goto cleanup;
4310 	}
4311 
4312 	/*
4313 	 * Redirect zones only require minimal configuration.
4314 	 */
4315 	if (strcasecmp(ztypestr, "redirect") == 0) {
4316 		if (view->redirect != NULL) {
4317 			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4318 				    "redirect zone already exists");
4319 			result = ISC_R_EXISTS;
4320 			goto cleanup;
4321 		}
4322 		result = dns_viewlist_find(viewlist, view->name,
4323 					   view->rdclass, &pview);
4324 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4325 			goto cleanup;
4326 		if (pview != NULL && pview->redirect != NULL) {
4327 			dns_zone_attach(pview->redirect, &zone);
4328 			dns_zone_setview(zone, view);
4329 		} else {
4330 			CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
4331 						     &zone));
4332 			CHECK(dns_zone_setorigin(zone, origin));
4333 			dns_zone_setview(zone, view);
4334 			CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
4335 						     zone));
4336 			dns_zone_setstats(zone, ns_g_server->zonestats);
4337 		}
4338 		CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf,
4339 					zone, NULL));
4340 		dns_zone_attach(zone, &view->redirect);
4341 		goto cleanup;
4342 	}
4343 
4344 	/*
4345 	 * Check for duplicates in the new zone table.
4346 	 */
4347 	result = dns_view_findzone(view, origin, &dupzone);
4348 	if (result == ISC_R_SUCCESS) {
4349 		/*
4350 		 * We already have this zone!
4351 		 */
4352 		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
4353 			    "zone '%s' already exists", zname);
4354 		dns_zone_detach(&dupzone);
4355 		result = ISC_R_EXISTS;
4356 		goto cleanup;
4357 	}
4358 	INSIST(dupzone == NULL);
4359 
4360 	/*
4361 	 * Note whether this is a response policy zone and which one if so.
4362 	 */
4363 	for (rpz_num = 0; ; ++rpz_num) {
4364 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones) {
4365 			rpz_num = DNS_RPZ_INVALID_NUM;
4366 			break;
4367 		}
4368 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
4369 			break;
4370 	}
4371 
4372 	/*
4373 	 * See if we can reuse an existing zone.  This is
4374 	 * only possible if all of these are true:
4375 	 *   - The zone's view exists
4376 	 *   - A zone with the right name exists in the view
4377 	 *   - The zone is compatible with the config
4378 	 *     options (e.g., an existing master zone cannot
4379 	 *     be reused if the options specify a slave zone)
4380 	 *   - The zone was not and is still not a response policy zone
4381 	 *     or the zone is a policy zone with an unchanged number
4382 	 *     and we are using the old policy zone summary data.
4383 	 */
4384 	result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
4385 				   view->rdclass, &pview);
4386 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4387 		goto cleanup;
4388 	if (pview != NULL)
4389 		result = dns_view_findzone(pview, origin, &zone);
4390 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4391 		goto cleanup;
4392 
4393 	if (zone != NULL && !ns_zone_reusable(zone, zconfig))
4394 		dns_zone_detach(&zone);
4395 
4396 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
4397 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
4398 		dns_zone_detach(&zone);
4399 
4400 	if (zone != NULL) {
4401 		/*
4402 		 * We found a reusable zone.  Make it use the
4403 		 * new view.
4404 		 */
4405 		dns_zone_setview(zone, view);
4406 		if (view->acache != NULL)
4407 			dns_zone_setacache(zone, view->acache);
4408 	} else {
4409 		/*
4410 		 * We cannot reuse an existing zone, we have
4411 		 * to create a new one.
4412 		 */
4413 		CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
4414 		CHECK(dns_zone_setorigin(zone, origin));
4415 		dns_zone_setview(zone, view);
4416 		if (view->acache != NULL)
4417 			dns_zone_setacache(zone, view->acache);
4418 		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
4419 		dns_zone_setstats(zone, ns_g_server->zonestats);
4420 	}
4421 
4422 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
4423 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
4424 		if (result != ISC_R_SUCCESS) {
4425 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4426 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4427 				      "zone '%s': incompatible"
4428 				      " masterfile-format or database"
4429 				      " for a response policy zone",
4430 				      zname);
4431 			goto cleanup;
4432 		}
4433 	}
4434 
4435 	/*
4436 	 * If the zone contains a 'forwarders' statement, configure
4437 	 * selective forwarding.
4438 	 */
4439 	forwarders = NULL;
4440 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
4441 	{
4442 		forwardtype = NULL;
4443 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
4444 		CHECK(configure_forward(config, view, origin, forwarders,
4445 					forwardtype));
4446 	}
4447 
4448 	/*
4449 	 * Stub and forward zones may also refer to delegation only points.
4450 	 */
4451 	only = NULL;
4452 	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
4453 	{
4454 		if (cfg_obj_asboolean(only))
4455 			CHECK(dns_view_adddelegationonly(view, origin));
4456 	}
4457 
4458 	/*
4459 	 * Mark whether the zone was originally added at runtime or not
4460 	 */
4461 	dns_zone_setadded(zone, added);
4462 
4463 	signing = NULL;
4464 	if ((strcasecmp(ztypestr, "master") == 0 ||
4465 	     strcasecmp(ztypestr, "slave") == 0) &&
4466 	    cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
4467 	    cfg_obj_asboolean(signing))
4468 	{
4469 		dns_zone_getraw(zone, &raw);
4470 		if (raw == NULL) {
4471 			CHECK(dns_zone_create(&raw, mctx));
4472 			CHECK(dns_zone_setorigin(raw, origin));
4473 			dns_zone_setview(raw, view);
4474 			if (view->acache != NULL)
4475 				dns_zone_setacache(raw, view->acache);
4476 			dns_zone_setstats(raw, ns_g_server->zonestats);
4477 			CHECK(dns_zone_link(zone, raw));
4478 		}
4479 	}
4480 
4481 	/*
4482 	 * Configure the zone.
4483 	 */
4484 	CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw));
4485 
4486 	/*
4487 	 * Add the zone to its view in the new view list.
4488 	 */
4489 	CHECK(dns_view_addzone(view, zone));
4490 
4491 	/*
4492 	 * Ensure that zone keys are reloaded on reconfig
4493 	 */
4494 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
4495 		dns_zone_rekey(zone, ISC_FALSE);
4496 
4497  cleanup:
4498 	if (zone != NULL)
4499 		dns_zone_detach(&zone);
4500 	if (raw != NULL)
4501 		dns_zone_detach(&raw);
4502 	if (pview != NULL)
4503 		dns_view_detach(&pview);
4504 
4505 	return (result);
4506 }
4507 
4508 /*
4509  * Configure built-in zone for storing managed-key data.
4510  */
4511 
4512 #define KEYZONE "managed-keys.bind"
4513 #define MKEYS ".mkeys"
4514 
4515 static isc_result_t
4516 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
4517 	isc_result_t result;
4518 	dns_view_t *pview = NULL;
4519 	dns_zone_t *zone = NULL;
4520 	dns_acl_t *none = NULL;
4521 	char filename[PATH_MAX];
4522 	char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)];
4523 	int n;
4524 
4525 	REQUIRE(view != NULL);
4526 
4527 	/* See if we can re-use an existing keydata zone. */
4528 	result = dns_viewlist_find(&ns_g_server->viewlist,
4529 				   view->name, view->rdclass,
4530 				   &pview);
4531 	if (result != ISC_R_NOTFOUND &&
4532 	    result != ISC_R_SUCCESS)
4533 		return (result);
4534 
4535 	if (pview != NULL && pview->managed_keys != NULL) {
4536 		dns_zone_attach(pview->managed_keys, &view->managed_keys);
4537 		dns_zone_setview(pview->managed_keys, view);
4538 		dns_view_detach(&pview);
4539 		dns_zone_synckeyzone(view->managed_keys);
4540 		return (ISC_R_SUCCESS);
4541 	}
4542 
4543 	/* No existing keydata zone was found; create one */
4544 	CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
4545 	CHECK(dns_zone_setorigin(zone, dns_rootname));
4546 
4547 	isc_sha256_data((void *)view->name, strlen(view->name), buffer);
4548 	strcat(buffer, MKEYS);
4549 	n = snprintf(filename, sizeof(filename), "%s%s%s",
4550 		     directory ? directory : "", directory ? "/" : "",
4551 		     strcmp(view->name, "_default") == 0 ? KEYZONE : buffer);
4552 	if (n < 0 || (size_t)n >= sizeof(filename)) {
4553 		result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE;
4554 		goto cleanup;
4555 	}
4556 	CHECK(dns_zone_setfile(zone, filename));
4557 
4558 	dns_zone_setview(zone, view);
4559 	dns_zone_settype(zone, dns_zone_key);
4560 	dns_zone_setclass(zone, view->rdclass);
4561 
4562 	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
4563 
4564 	if (view->acache != NULL)
4565 		dns_zone_setacache(zone, view->acache);
4566 
4567 	CHECK(dns_acl_none(mctx, &none));
4568 	dns_zone_setqueryacl(zone, none);
4569 	dns_zone_setqueryonacl(zone, none);
4570 	dns_acl_detach(&none);
4571 
4572 	dns_zone_setdialup(zone, dns_dialuptype_no);
4573 	dns_zone_setnotifytype(zone, dns_notifytype_no);
4574 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
4575 	dns_zone_setjournalsize(zone, 0);
4576 
4577 	dns_zone_setstats(zone, ns_g_server->zonestats);
4578 	CHECK(setquerystats(zone, mctx, dns_zonestat_none));
4579 
4580 	if (view->managed_keys != NULL)
4581 		dns_zone_detach(&view->managed_keys);
4582 	dns_zone_attach(zone, &view->managed_keys);
4583 
4584 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4585 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4586 		      "set up managed keys zone for view %s, file '%s'",
4587 		      view->name, filename);
4588 
4589 cleanup:
4590 	if (zone != NULL)
4591 		dns_zone_detach(&zone);
4592 	if (none != NULL)
4593 		dns_acl_detach(&none);
4594 
4595 	return (result);
4596 }
4597 
4598 /*
4599  * Configure a single server quota.
4600  */
4601 static void
4602 configure_server_quota(const cfg_obj_t **maps, const char *name,
4603 		       isc_quota_t *quota)
4604 {
4605 	const cfg_obj_t *obj = NULL;
4606 	isc_result_t result;
4607 
4608 	result = ns_config_get(maps, name, &obj);
4609 	INSIST(result == ISC_R_SUCCESS);
4610 	isc_quota_max(quota, cfg_obj_asuint32(obj));
4611 }
4612 
4613 /*
4614  * This function is called as soon as the 'directory' statement has been
4615  * parsed.  This can be extended to support other options if necessary.
4616  */
4617 static isc_result_t
4618 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
4619 	isc_result_t result;
4620 	const char *directory;
4621 
4622 	REQUIRE(strcasecmp("directory", clausename) == 0);
4623 
4624 	UNUSED(arg);
4625 	UNUSED(clausename);
4626 
4627 	/*
4628 	 * Change directory.
4629 	 */
4630 	directory = cfg_obj_asstring(obj);
4631 
4632 	if (! isc_file_ischdiridempotent(directory))
4633 		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
4634 			    "option 'directory' contains relative path '%s'",
4635 			    directory);
4636 
4637 	result = isc_dir_chdir(directory);
4638 	if (result != ISC_R_SUCCESS) {
4639 		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
4640 			    "change directory to '%s' failed: %s",
4641 			    directory, isc_result_totext(result));
4642 		return (result);
4643 	}
4644 
4645 	return (ISC_R_SUCCESS);
4646 }
4647 
4648 static void
4649 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
4650 	isc_boolean_t match_mapped = server->aclenv.match_mapped;
4651 
4652 	ns_interfacemgr_scan(server->interfacemgr, verbose);
4653 	/*
4654 	 * Update the "localhost" and "localnets" ACLs to match the
4655 	 * current set of network interfaces.
4656 	 */
4657 	dns_aclenv_copy(&server->aclenv,
4658 			ns_interfacemgr_getaclenv(server->interfacemgr));
4659 
4660 	server->aclenv.match_mapped = match_mapped;
4661 }
4662 
4663 static isc_result_t
4664 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
4665 	      isc_dscp_t dscp, isc_boolean_t wcardport_ok)
4666 {
4667 	ns_listenelt_t *lelt = NULL;
4668 	dns_acl_t *src_acl = NULL;
4669 	isc_result_t result;
4670 	isc_sockaddr_t any_sa6;
4671 	isc_netaddr_t netaddr;
4672 
4673 	REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
4674 
4675 	isc_sockaddr_any6(&any_sa6);
4676 	if (!isc_sockaddr_equal(&any_sa6, addr) &&
4677 	    (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
4678 		isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
4679 
4680 		result = dns_acl_create(mctx, 0, &src_acl);
4681 		if (result != ISC_R_SUCCESS)
4682 			return (result);
4683 
4684 		result = dns_iptable_addprefix(src_acl->iptable,
4685 					       &netaddr, 128, ISC_TRUE);
4686 		if (result != ISC_R_SUCCESS)
4687 			goto clean;
4688 
4689 		result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
4690 					     dscp, src_acl, &lelt);
4691 		if (result != ISC_R_SUCCESS)
4692 			goto clean;
4693 		ISC_LIST_APPEND(list->elts, lelt, link);
4694 	}
4695 
4696 	return (ISC_R_SUCCESS);
4697 
4698  clean:
4699 	INSIST(lelt == NULL);
4700 	dns_acl_detach(&src_acl);
4701 
4702 	return (result);
4703 }
4704 
4705 /*
4706  * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
4707  * to update the listening interfaces accordingly.
4708  * We currently only consider IPv6, because this only affects IPv6 wildcard
4709  * sockets.
4710  */
4711 static void
4712 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
4713 	isc_result_t result;
4714 	ns_listenlist_t *list = NULL;
4715 	dns_view_t *view;
4716 	dns_zone_t *zone, *next;
4717 	isc_sockaddr_t addr, *addrp;
4718 	isc_dscp_t dscp = -1;
4719 
4720 	result = ns_listenlist_create(mctx, &list);
4721 	if (result != ISC_R_SUCCESS)
4722 		return;
4723 
4724 	for (view = ISC_LIST_HEAD(server->viewlist);
4725 	     view != NULL;
4726 	     view = ISC_LIST_NEXT(view, link)) {
4727 		dns_dispatch_t *dispatch6;
4728 
4729 		dispatch6 = dns_resolver_dispatchv6(view->resolver);
4730 		if (dispatch6 == NULL)
4731 			continue;
4732 		result = dns_dispatch_getlocaladdress(dispatch6, &addr);
4733 		if (result != ISC_R_SUCCESS)
4734 			goto fail;
4735 
4736 		/*
4737 		 * We always add non-wildcard address regardless of whether
4738 		 * the port is 'any' (the fourth arg is TRUE): if the port is
4739 		 * specific, we need to add it since it may conflict with a
4740 		 * listening interface; if it's zero, we'll dynamically open
4741 		 * query ports, and some of them may override an existing
4742 		 * wildcard IPv6 port.
4743 		 */
4744 		/* XXXMPA fix dscp */
4745 		result = add_listenelt(mctx, list, &addr, dscp, ISC_TRUE);
4746 		if (result != ISC_R_SUCCESS)
4747 			goto fail;
4748 	}
4749 
4750 	zone = NULL;
4751 	for (result = dns_zone_first(server->zonemgr, &zone);
4752 	     result == ISC_R_SUCCESS;
4753 	     next = NULL, result = dns_zone_next(zone, &next), zone = next) {
4754 		dns_view_t *zoneview;
4755 
4756 		/*
4757 		 * At this point the zone list may contain a stale zone
4758 		 * just removed from the configuration.  To see the validity,
4759 		 * check if the corresponding view is in our current view list.
4760 		 * There may also be old zones that are still in the process
4761 		 * of shutting down and have detached from their old view
4762 		 * (zoneview == NULL).
4763 		 */
4764 		zoneview = dns_zone_getview(zone);
4765 		if (zoneview == NULL)
4766 			continue;
4767 		for (view = ISC_LIST_HEAD(server->viewlist);
4768 		     view != NULL && view != zoneview;
4769 		     view = ISC_LIST_NEXT(view, link))
4770 			;
4771 		if (view == NULL)
4772 			continue;
4773 
4774 		addrp = dns_zone_getnotifysrc6(zone);
4775 		dscp = dns_zone_getnotifysrc6dscp(zone);
4776 		result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
4777 		if (result != ISC_R_SUCCESS)
4778 			goto fail;
4779 
4780 		addrp = dns_zone_getxfrsource6(zone);
4781 		dscp = dns_zone_getxfrsource6dscp(zone);
4782 		result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
4783 		if (result != ISC_R_SUCCESS)
4784 			goto fail;
4785 	}
4786 
4787 	ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
4788 
4789  clean:
4790 	ns_listenlist_detach(&list);
4791 	return;
4792 
4793  fail:
4794 	/*
4795 	 * Even when we failed the procedure, most of other interfaces
4796 	 * should work correctly.  We therefore just warn it.
4797 	 */
4798 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4799 		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4800 		      "could not adjust the listen-on list; "
4801 		      "some interfaces may not work");
4802 	goto clean;
4803 }
4804 
4805 /*
4806  * This event callback is invoked to do periodic network interface
4807  * scanning.  It is also called by ns_server_scan_interfaces(),
4808  * invoked by "rndc scan"
4809  */
4810 
4811 static void
4812 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
4813 	isc_result_t result;
4814 	ns_server_t *server = (ns_server_t *) event->ev_arg;
4815 	INSIST(task == server->task);
4816 	UNUSED(task);
4817 
4818 	isc_event_free(&event);
4819 
4820 	/*
4821 	 * XXX should scan interfaces unlocked and get exclusive access
4822 	 * only to replace ACLs.
4823 	 */
4824 	result = isc_task_beginexclusive(server->task);
4825 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
4826 	scan_interfaces(server, ISC_FALSE);
4827 	isc_task_endexclusive(server->task);
4828 }
4829 
4830 static void
4831 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
4832 	ns_server_t *server = (ns_server_t *) event->ev_arg;
4833 	dns_view_t *view;
4834 
4835 	UNUSED(task);
4836 	isc_event_free(&event);
4837 	view = ISC_LIST_HEAD(server->viewlist);
4838 	while (view != NULL) {
4839 		dns_view_dialup(view);
4840 		view = ISC_LIST_NEXT(view, link);
4841 	}
4842 }
4843 
4844 static void
4845 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
4846 	static unsigned int oldrequests = 0;
4847 	unsigned int requests = ns_client_requests;
4848 
4849 	UNUSED(task);
4850 	isc_event_free(&event);
4851 
4852 	/*
4853 	 * Don't worry about wrapping as the overflow result will be right.
4854 	 */
4855 	dns_pps = (requests - oldrequests) / 1200;
4856 	oldrequests = requests;
4857 }
4858 
4859 /*
4860  * Replace the current value of '*field', a dynamically allocated
4861  * string or NULL, with a dynamically allocated copy of the
4862  * null-terminated string pointed to by 'value', or NULL.
4863  */
4864 static isc_result_t
4865 setstring(ns_server_t *server, char **field, const char *value) {
4866 	char *copy;
4867 
4868 	if (value != NULL) {
4869 		copy = isc_mem_strdup(server->mctx, value);
4870 		if (copy == NULL)
4871 			return (ISC_R_NOMEMORY);
4872 	} else {
4873 		copy = NULL;
4874 	}
4875 
4876 	if (*field != NULL)
4877 		isc_mem_free(server->mctx, *field);
4878 
4879 	*field = copy;
4880 	return (ISC_R_SUCCESS);
4881 }
4882 
4883 /*
4884  * Replace the current value of '*field', a dynamically allocated
4885  * string or NULL, with another dynamically allocated string
4886  * or NULL if whether 'obj' is a string or void value, respectively.
4887  */
4888 static isc_result_t
4889 setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
4890 	if (cfg_obj_isvoid(obj))
4891 		return (setstring(server, field, NULL));
4892 	else
4893 		return (setstring(server, field, cfg_obj_asstring(obj)));
4894 }
4895 
4896 static void
4897 set_limit(const cfg_obj_t **maps, const char *configname,
4898 	  const char *description, isc_resource_t resourceid,
4899 	  isc_resourcevalue_t defaultvalue)
4900 {
4901 	const cfg_obj_t *obj = NULL;
4902 	const char *resource;
4903 	isc_resourcevalue_t value;
4904 	isc_result_t result;
4905 
4906 	if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
4907 		return;
4908 
4909 	if (cfg_obj_isstring(obj)) {
4910 		resource = cfg_obj_asstring(obj);
4911 		if (strcasecmp(resource, "unlimited") == 0)
4912 			value = ISC_RESOURCE_UNLIMITED;
4913 		else {
4914 			INSIST(strcasecmp(resource, "default") == 0);
4915 			value = defaultvalue;
4916 		}
4917 	} else
4918 		value = cfg_obj_asuint64(obj);
4919 
4920 	result = isc_resource_setlimit(resourceid, value);
4921 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4922 		      result == ISC_R_SUCCESS ?
4923 			ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
4924 		      "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
4925 		      description, value, isc_result_totext(result));
4926 }
4927 
4928 #define SETLIMIT(cfgvar, resource, description) \
4929 	set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
4930 		  ns_g_init ## resource)
4931 
4932 static void
4933 set_limits(const cfg_obj_t **maps) {
4934 	SETLIMIT("stacksize", stacksize, "stack size");
4935 	SETLIMIT("datasize", datasize, "data size");
4936 	SETLIMIT("coresize", coresize, "core size");
4937 	SETLIMIT("files", openfiles, "open files");
4938 }
4939 
4940 static void
4941 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
4942 		 isc_boolean_t positive)
4943 {
4944 	const cfg_listelt_t *element;
4945 
4946 	for (element = cfg_list_first(ports);
4947 	     element != NULL;
4948 	     element = cfg_list_next(element)) {
4949 		const cfg_obj_t *obj = cfg_listelt_value(element);
4950 
4951 		if (cfg_obj_isuint32(obj)) {
4952 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
4953 
4954 			if (positive)
4955 				isc_portset_add(portset, port);
4956 			else
4957 				isc_portset_remove(portset, port);
4958 		} else {
4959 			const cfg_obj_t *obj_loport, *obj_hiport;
4960 			in_port_t loport, hiport;
4961 
4962 			obj_loport = cfg_tuple_get(obj, "loport");
4963 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
4964 			obj_hiport = cfg_tuple_get(obj, "hiport");
4965 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
4966 
4967 			if (positive)
4968 				isc_portset_addrange(portset, loport, hiport);
4969 			else {
4970 				isc_portset_removerange(portset, loport,
4971 							hiport);
4972 			}
4973 		}
4974 	}
4975 }
4976 
4977 static isc_result_t
4978 removed(dns_zone_t *zone, void *uap) {
4979 	const char *type;
4980 
4981 	if (dns_zone_getview(zone) != uap)
4982 		return (ISC_R_SUCCESS);
4983 
4984 	switch (dns_zone_gettype(zone)) {
4985 	case dns_zone_master:
4986 		type = "master";
4987 		break;
4988 	case dns_zone_slave:
4989 		type = "slave";
4990 		break;
4991 	case dns_zone_stub:
4992 		type = "stub";
4993 		break;
4994 	case dns_zone_staticstub:
4995 		type = "static-stub";
4996 		break;
4997 	case dns_zone_redirect:
4998 		type = "redirect";
4999 		break;
5000 	default:
5001 		type = "other";
5002 		break;
5003 	}
5004 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
5005 	return (ISC_R_SUCCESS);
5006 }
5007 
5008 static void
5009 cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
5010 	if (server->session_keyfile != NULL) {
5011 		isc_file_remove(server->session_keyfile);
5012 		isc_mem_free(mctx, server->session_keyfile);
5013 		server->session_keyfile = NULL;
5014 	}
5015 
5016 	if (server->session_keyname != NULL) {
5017 		if (dns_name_dynamic(server->session_keyname))
5018 			dns_name_free(server->session_keyname, mctx);
5019 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
5020 		server->session_keyname = NULL;
5021 	}
5022 
5023 	if (server->sessionkey != NULL)
5024 		dns_tsigkey_detach(&server->sessionkey);
5025 
5026 	server->session_keyalg = DST_ALG_UNKNOWN;
5027 	server->session_keybits = 0;
5028 }
5029 
5030 static isc_result_t
5031 generate_session_key(const char *filename, const char *keynamestr,
5032 		     dns_name_t *keyname, const char *algstr,
5033 		     dns_name_t *algname, unsigned int algtype,
5034 		     isc_uint16_t bits, isc_mem_t *mctx,
5035 		     dns_tsigkey_t **tsigkeyp)
5036 {
5037 	isc_result_t result = ISC_R_SUCCESS;
5038 	dst_key_t *key = NULL;
5039 	isc_buffer_t key_txtbuffer;
5040 	isc_buffer_t key_rawbuffer;
5041 	char key_txtsecret[256];
5042 	char key_rawsecret[64];
5043 	isc_region_t key_rawregion;
5044 	isc_stdtime_t now;
5045 	dns_tsigkey_t *tsigkey = NULL;
5046 	FILE *fp = NULL;
5047 
5048 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5049 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5050 		      "generating session key for dynamic DNS");
5051 
5052 	/* generate key */
5053 	result = dst_key_generate(keyname, algtype, bits, 1, 0,
5054 				  DNS_KEYPROTO_ANY, dns_rdataclass_in,
5055 				  mctx, &key);
5056 	if (result != ISC_R_SUCCESS)
5057 		return (result);
5058 
5059 	/*
5060 	 * Dump the key to the buffer for later use.  Should be done before
5061 	 * we transfer the ownership of key to tsigkey.
5062 	 */
5063 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
5064 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
5065 
5066 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
5067 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
5068 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
5069 
5070 	/* Store the key in tsigkey. */
5071 	isc_stdtime_get(&now);
5072 	CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
5073 					ISC_FALSE, NULL, now, now, mctx, NULL,
5074 					&tsigkey));
5075 
5076 	/* Dump the key to the key file. */
5077 	fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
5078 	if (fp == NULL) {
5079 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5080 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5081 			      "could not create %s", filename);
5082 		result = ISC_R_NOPERM;
5083 		goto cleanup;
5084 	}
5085 
5086 	fprintf(fp, "key \"%s\" {\n"
5087 		"\talgorithm %s;\n"
5088 		"\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
5089 		(int) isc_buffer_usedlength(&key_txtbuffer),
5090 		(char*) isc_buffer_base(&key_txtbuffer));
5091 
5092 	CHECK(isc_stdio_flush(fp));
5093 	CHECK(isc_stdio_close(fp));
5094 
5095 	dst_key_free(&key);
5096 
5097 	*tsigkeyp = tsigkey;
5098 
5099 	return (ISC_R_SUCCESS);
5100 
5101   cleanup:
5102 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5103 		      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5104 		      "failed to generate session key "
5105 		      "for dynamic DNS: %s", isc_result_totext(result));
5106 	if (fp != NULL) {
5107 		if (isc_file_exists(filename))
5108 			(void)isc_file_remove(filename);
5109 		(void)isc_stdio_close(fp);
5110 	}
5111 	if (tsigkey != NULL)
5112 		dns_tsigkey_detach(&tsigkey);
5113 	if (key != NULL)
5114 		dst_key_free(&key);
5115 
5116 	return (result);
5117 }
5118 
5119 static isc_result_t
5120 configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
5121 		      isc_mem_t *mctx)
5122 {
5123 	const char *keyfile, *keynamestr, *algstr;
5124 	unsigned int algtype;
5125 	dns_fixedname_t fname;
5126 	dns_name_t *keyname, *algname;
5127 	isc_buffer_t buffer;
5128 	isc_uint16_t bits;
5129 	const cfg_obj_t *obj;
5130 	isc_boolean_t need_deleteold = ISC_FALSE;
5131 	isc_boolean_t need_createnew = ISC_FALSE;
5132 	isc_result_t result;
5133 
5134 	obj = NULL;
5135 	result = ns_config_get(maps, "session-keyfile", &obj);
5136 	if (result == ISC_R_SUCCESS) {
5137 		if (cfg_obj_isvoid(obj))
5138 			keyfile = NULL; /* disable it */
5139 		else
5140 			keyfile = cfg_obj_asstring(obj);
5141 	} else
5142 		keyfile = ns_g_defaultsessionkeyfile;
5143 
5144 	obj = NULL;
5145 	result = ns_config_get(maps, "session-keyname", &obj);
5146 	INSIST(result == ISC_R_SUCCESS);
5147 	keynamestr = cfg_obj_asstring(obj);
5148 	dns_fixedname_init(&fname);
5149 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
5150 	isc_buffer_add(&buffer, strlen(keynamestr));
5151 	keyname = dns_fixedname_name(&fname);
5152 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
5153 	if (result != ISC_R_SUCCESS)
5154 		return (result);
5155 
5156 	obj = NULL;
5157 	result = ns_config_get(maps, "session-keyalg", &obj);
5158 	INSIST(result == ISC_R_SUCCESS);
5159 	algstr = cfg_obj_asstring(obj);
5160 	algname = NULL;
5161 	result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
5162 	if (result != ISC_R_SUCCESS) {
5163 		const char *s = " (keeping current key)";
5164 
5165 		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
5166 			    "unsupported or unknown algorithm '%s'%s",
5167 			    algstr,
5168 			    server->session_keyfile != NULL ? s : "");
5169 		return (result);
5170 	}
5171 
5172 	/* See if we need to (re)generate a new key. */
5173 	if (keyfile == NULL) {
5174 		if (server->session_keyfile != NULL)
5175 			need_deleteold = ISC_TRUE;
5176 	} else if (server->session_keyfile == NULL)
5177 		need_createnew = ISC_TRUE;
5178 	else if (strcmp(keyfile, server->session_keyfile) != 0 ||
5179 		 !dns_name_equal(server->session_keyname, keyname) ||
5180 		 server->session_keyalg != algtype ||
5181 		 server->session_keybits != bits) {
5182 		need_deleteold = ISC_TRUE;
5183 		need_createnew = ISC_TRUE;
5184 	}
5185 
5186 	if (need_deleteold) {
5187 		INSIST(server->session_keyfile != NULL);
5188 		INSIST(server->session_keyname != NULL);
5189 		INSIST(server->sessionkey != NULL);
5190 
5191 		cleanup_session_key(server, mctx);
5192 	}
5193 
5194 	if (need_createnew) {
5195 		INSIST(server->sessionkey == NULL);
5196 		INSIST(server->session_keyfile == NULL);
5197 		INSIST(server->session_keyname == NULL);
5198 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
5199 		INSIST(server->session_keybits == 0);
5200 
5201 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
5202 		if (server->session_keyname == NULL)
5203 			goto cleanup;
5204 		dns_name_init(server->session_keyname, NULL);
5205 		CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
5206 
5207 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
5208 		if (server->session_keyfile == NULL)
5209 			goto cleanup;
5210 
5211 		server->session_keyalg = algtype;
5212 		server->session_keybits = bits;
5213 
5214 		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
5215 					   algname, algtype, bits, mctx,
5216 					   &server->sessionkey));
5217 	}
5218 
5219 	return (result);
5220 
5221   cleanup:
5222 	cleanup_session_key(server, mctx);
5223 	return (result);
5224 }
5225 
5226 static isc_result_t
5227 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
5228 	       cfg_parser_t *parser, cfg_aclconfctx_t *actx)
5229 {
5230 	isc_result_t result = ISC_R_SUCCESS;
5231 	isc_boolean_t allow = ISC_FALSE;
5232 	struct cfg_context *nzcfg = NULL;
5233 	cfg_parser_t *nzparser = NULL;
5234 	cfg_obj_t *nzconfig = NULL;
5235 	const cfg_obj_t *maps[4];
5236 	const cfg_obj_t *options = NULL, *voptions = NULL;
5237 	const cfg_obj_t *nz = NULL;
5238 	int i = 0;
5239 
5240 	REQUIRE (config != NULL);
5241 
5242 	if (vconfig != NULL)
5243 		voptions = cfg_tuple_get(vconfig, "options");
5244 	if (voptions != NULL)
5245 		maps[i++] = voptions;
5246 	result = cfg_map_get(config, "options", &options);
5247 	if (result == ISC_R_SUCCESS)
5248 		maps[i++] = options;
5249 	maps[i++] = ns_g_defaults;
5250 	maps[i] = NULL;
5251 
5252 	result = ns_config_get(maps, "allow-new-zones", &nz);
5253 	if (result == ISC_R_SUCCESS)
5254 		allow = cfg_obj_asboolean(nz);
5255 
5256 	if (!allow) {
5257 		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
5258 		return (ISC_R_SUCCESS);
5259 	}
5260 
5261 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
5262 	if (nzcfg == NULL) {
5263 		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
5264 		return (ISC_R_NOMEMORY);
5265 	}
5266 
5267 	dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
5268 
5269 	memset(nzcfg, 0, sizeof(*nzcfg));
5270 	isc_mem_attach(view->mctx, &nzcfg->mctx);
5271 	cfg_obj_attach(config, &nzcfg->config);
5272 	cfg_parser_attach(parser, &nzcfg->parser);
5273 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
5274 
5275 	/*
5276 	 * Attempt to create a parser and parse the newzones
5277 	 * file.  If successful, preserve both; otherwise leave
5278 	 * them NULL.
5279 	 */
5280 	result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser);
5281 	if (result == ISC_R_SUCCESS)
5282 		result = cfg_parse_file(nzparser, view->new_zone_file,
5283 					&cfg_type_newzones, &nzconfig);
5284 	if (result == ISC_R_SUCCESS) {
5285 		cfg_parser_attach(nzparser, &nzcfg->nzparser);
5286 		cfg_obj_attach(nzconfig, &nzcfg->nzconfig);
5287 	}
5288 
5289 	if (nzparser != NULL) {
5290 		if (nzconfig != NULL)
5291 			cfg_obj_destroy(nzparser, &nzconfig);
5292 		cfg_parser_destroy(&nzparser);
5293 	}
5294 
5295 	return (ISC_R_SUCCESS);
5296 }
5297 
5298 static int
5299 count_zones(const cfg_obj_t *conf) {
5300 	const cfg_obj_t *zonelist = NULL;
5301 	const cfg_listelt_t *element;
5302 	int n = 0;
5303 
5304 	REQUIRE(conf != NULL);
5305 
5306 	cfg_map_get(conf, "zone", &zonelist);
5307 	for (element = cfg_list_first(zonelist);
5308 	     element != NULL;
5309 	     element = cfg_list_next(element))
5310 		n++;
5311 
5312 	return (n);
5313 }
5314 
5315 static isc_result_t
5316 load_configuration(const char *filename, ns_server_t *server,
5317 		   isc_boolean_t first_time)
5318 {
5319 	cfg_obj_t *config = NULL, *bindkeys = NULL;
5320 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
5321 	const cfg_listelt_t *element;
5322 	const cfg_obj_t *builtin_views;
5323 	const cfg_obj_t *maps[3];
5324 	const cfg_obj_t *obj;
5325 	const cfg_obj_t *options;
5326 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
5327 	const cfg_obj_t *views;
5328 	dns_view_t *view = NULL;
5329 	dns_view_t *view_next;
5330 	dns_viewlist_t tmpviewlist;
5331 	dns_viewlist_t viewlist, builtin_viewlist;
5332 	in_port_t listen_port, udpport_low, udpport_high;
5333 	int i;
5334 	int num_zones = 0;
5335 	isc_boolean_t exclusive = ISC_FALSE;
5336 	isc_interval_t interval;
5337 	isc_logconfig_t *logc = NULL;
5338 	isc_portset_t *v4portset = NULL;
5339 	isc_portset_t *v6portset = NULL;
5340 	isc_resourcevalue_t nfiles;
5341 	isc_result_t result, tresult;
5342 	isc_uint32_t heartbeat_interval;
5343 	isc_uint32_t interface_interval;
5344 	isc_uint32_t reserved;
5345 	isc_uint32_t udpsize;
5346 	ns_cache_t *nsc;
5347 	ns_cachelist_t cachelist, tmpcachelist;
5348 	struct cfg_context *nzctx;
5349 	unsigned int maxsocks;
5350 
5351 	ISC_LIST_INIT(viewlist);
5352 	ISC_LIST_INIT(builtin_viewlist);
5353 	ISC_LIST_INIT(cachelist);
5354 
5355 	/* Create the ACL configuration context */
5356 	if (ns_g_aclconfctx != NULL)
5357 		cfg_aclconfctx_detach(&ns_g_aclconfctx);
5358 	CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
5359 
5360 	/*
5361 	 * Parse the global default pseudo-config file.
5362 	 */
5363 	if (first_time) {
5364 		CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
5365 		RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
5366 					  &ns_g_defaults) == ISC_R_SUCCESS);
5367 	}
5368 
5369 	/*
5370 	 * Parse the configuration file using the new config code.
5371 	 */
5372 	result = ISC_R_FAILURE;
5373 	config = NULL;
5374 
5375 	/*
5376 	 * Unless this is lwresd with the -C option, parse the config file.
5377 	 */
5378 	if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
5379 		isc_log_write(ns_g_lctx,
5380 			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5381 			      ISC_LOG_INFO, "loading configuration from '%s'",
5382 			      filename);
5383 		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
5384 		cfg_parser_setcallback(conf_parser, directory_callback, NULL);
5385 		result = cfg_parse_file(conf_parser, filename,
5386 					&cfg_type_namedconf, &config);
5387 	}
5388 
5389 	/*
5390 	 * If this is lwresd with the -C option, or lwresd with no -C or -c
5391 	 * option where the above parsing failed, parse resolv.conf.
5392 	 */
5393 	if (ns_g_lwresdonly &&
5394 	    (lwresd_g_useresolvconf ||
5395 	     (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
5396 	{
5397 		isc_log_write(ns_g_lctx,
5398 			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5399 			      ISC_LOG_INFO, "loading configuration from '%s'",
5400 			      lwresd_g_resolvconffile);
5401 		if (conf_parser != NULL)
5402 			cfg_parser_destroy(&conf_parser);
5403 		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
5404 		result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
5405 						    &config);
5406 	}
5407 	CHECK(result);
5408 
5409 	/*
5410 	 * Check the validity of the configuration.
5411 	 */
5412 	CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
5413 
5414 	/*
5415 	 * Fill in the maps array, used for resolving defaults.
5416 	 */
5417 	i = 0;
5418 	options = NULL;
5419 	result = cfg_map_get(config, "options", &options);
5420 	if (result == ISC_R_SUCCESS)
5421 		maps[i++] = options;
5422 	maps[i++] = ns_g_defaults;
5423 	maps[i] = NULL;
5424 
5425 	/*
5426 	 * If bind.keys exists, load it.  If "dnssec-validation auto"
5427 	 * is turned on, the root key found there will be used as a
5428 	 * default trust anchor, and if "dnssec-lookaside auto" is
5429 	 * turned on, then the DLV key found there will too.
5430 	 */
5431 	obj = NULL;
5432 	result = ns_config_get(maps, "bindkeys-file", &obj);
5433 	INSIST(result == ISC_R_SUCCESS);
5434 	CHECKM(setstring(server, &server->bindkeysfile,
5435 	       cfg_obj_asstring(obj)), "strdup");
5436 
5437 	if (access(server->bindkeysfile, R_OK) == 0) {
5438 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5439 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5440 			      "reading built-in trusted "
5441 			      "keys from file '%s'", server->bindkeysfile);
5442 
5443 		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
5444 					&bindkeys_parser));
5445 
5446 		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
5447 					&cfg_type_bindkeys, &bindkeys);
5448 		CHECK(result);
5449 	}
5450 
5451 	/* Ensure exclusive access to configuration data. */
5452 	if (!exclusive) {
5453 		result = isc_task_beginexclusive(server->task);
5454 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5455 		exclusive = ISC_TRUE;
5456 	}
5457 
5458 	/*
5459 	 * Set process limits, which (usually) needs to be done as root.
5460 	 */
5461 	set_limits(maps);
5462 
5463 	/*
5464 	 * Check if max number of open sockets that the system allows is
5465 	 * sufficiently large.	Failing this condition is not necessarily fatal,
5466 	 * but may cause subsequent runtime failures for a busy recursive
5467 	 * server.
5468 	 */
5469 	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
5470 	if (result != ISC_R_SUCCESS)
5471 		maxsocks = 0;
5472 	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
5473 	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
5474 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5475 			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5476 			      "max open files (%" ISC_PRINT_QUADFORMAT "u)"
5477 			      " is smaller than max sockets (%u)",
5478 			      nfiles, maxsocks);
5479 	}
5480 
5481 	/*
5482 	 * Set the number of socket reserved for TCP, stdio etc.
5483 	 */
5484 	obj = NULL;
5485 	result = ns_config_get(maps, "reserved-sockets", &obj);
5486 	INSIST(result == ISC_R_SUCCESS);
5487 	reserved = cfg_obj_asuint32(obj);
5488 	if (maxsocks != 0) {
5489 		if (maxsocks < 128U)			/* Prevent underflow. */
5490 			reserved = 0;
5491 		else if (reserved > maxsocks - 128U)	/* Minimum UDP space. */
5492 			reserved = maxsocks - 128;
5493 	}
5494 	/* Minimum TCP/stdio space. */
5495 	if (reserved < 128U)
5496 		reserved = 128;
5497 	if (reserved + 128U > maxsocks && maxsocks != 0) {
5498 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5499 			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5500 			      "less than 128 UDP sockets available after "
5501 			      "applying 'reserved-sockets' and 'maxsockets'");
5502 	}
5503 	isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
5504 
5505 #ifdef HAVE_GEOIP
5506 	/*
5507 	 * Initialize GeoIP databases from the configured location.
5508 	 * This should happen before configuring any ACLs, so that we
5509 	 * know what databases are available and can reject any GeoIP
5510 	 * ACLs that can't work.
5511 	 */
5512 	obj = NULL;
5513 	result = ns_config_get(maps, "geoip-directory", &obj);
5514 	if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) {
5515 		char *dir;
5516 		DE_CONST(cfg_obj_asstring(obj), dir);
5517 		ns_geoip_load(dir);
5518 	} else
5519 		ns_geoip_load(NULL);
5520 	ns_g_aclconfctx->geoip = ns_g_geoip;
5521 #endif /* HAVE_GEOIP */
5522 
5523 	/*
5524 	 * Configure various server options.
5525 	 */
5526 	configure_server_quota(maps, "transfers-out", &server->xfroutquota);
5527 	configure_server_quota(maps, "tcp-clients", &server->tcpquota);
5528 	configure_server_quota(maps, "recursive-clients",
5529 			       &server->recursionquota);
5530 	if (server->recursionquota.max > 1000)
5531 		isc_quota_soft(&server->recursionquota,
5532 			       server->recursionquota.max - 100);
5533 	else
5534 		isc_quota_soft(&server->recursionquota, 0);
5535 
5536 	CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
5537 				 ns_g_aclconfctx, ns_g_mctx,
5538 				 &server->blackholeacl));
5539 	if (server->blackholeacl != NULL)
5540 		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
5541 					     server->blackholeacl);
5542 
5543 	obj = NULL;
5544 	result = ns_config_get(maps, "match-mapped-addresses", &obj);
5545 	INSIST(result == ISC_R_SUCCESS);
5546 	server->aclenv.match_mapped = cfg_obj_asboolean(obj);
5547 
5548 	CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
5549 	       "configuring statistics server(s)");
5550 
5551 	/*
5552 	 * Configure sets of UDP query source ports.
5553 	 */
5554 	CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
5555 	       "creating UDP port set");
5556 	CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
5557 	       "creating UDP port set");
5558 
5559 	usev4ports = NULL;
5560 	usev6ports = NULL;
5561 	avoidv4ports = NULL;
5562 	avoidv6ports = NULL;
5563 
5564 	(void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
5565 	if (usev4ports != NULL)
5566 		portset_fromconf(v4portset, usev4ports, ISC_TRUE);
5567 	else {
5568 		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
5569 					       &udpport_high),
5570 		       "get the default UDP/IPv4 port range");
5571 		if (udpport_low == udpport_high)
5572 			isc_portset_add(v4portset, udpport_low);
5573 		else {
5574 			isc_portset_addrange(v4portset, udpport_low,
5575 					     udpport_high);
5576 		}
5577 		if (!ns_g_disable4)
5578 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5579 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5580 				      "using default UDP/IPv4 port range: "
5581 				      "[%d, %d]", udpport_low, udpport_high);
5582 	}
5583 	(void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
5584 	if (avoidv4ports != NULL)
5585 		portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
5586 
5587 	(void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
5588 	if (usev6ports != NULL)
5589 		portset_fromconf(v6portset, usev6ports, ISC_TRUE);
5590 	else {
5591 		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
5592 					       &udpport_high),
5593 		       "get the default UDP/IPv6 port range");
5594 		if (udpport_low == udpport_high)
5595 			isc_portset_add(v6portset, udpport_low);
5596 		else {
5597 			isc_portset_addrange(v6portset, udpport_low,
5598 					     udpport_high);
5599 		}
5600 		if (!ns_g_disable6)
5601 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5602 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5603 				      "using default UDP/IPv6 port range: "
5604 				      "[%d, %d]", udpport_low, udpport_high);
5605 	}
5606 	(void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
5607 	if (avoidv6ports != NULL)
5608 		portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
5609 
5610 	dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
5611 
5612 	/*
5613 	 * Set the EDNS UDP size when we don't match a view.
5614 	 */
5615 	obj = NULL;
5616 	result = ns_config_get(maps, "edns-udp-size", &obj);
5617 	INSIST(result == ISC_R_SUCCESS);
5618 	udpsize = cfg_obj_asuint32(obj);
5619 	if (udpsize < 512)
5620 		udpsize = 512;
5621 	if (udpsize > 4096)
5622 		udpsize = 4096;
5623 	ns_g_udpsize = (isc_uint16_t)udpsize;
5624 
5625 	/*
5626 	 * Configure the zone manager.
5627 	 */
5628 	obj = NULL;
5629 	result = ns_config_get(maps, "transfers-in", &obj);
5630 	INSIST(result == ISC_R_SUCCESS);
5631 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
5632 
5633 	obj = NULL;
5634 	result = ns_config_get(maps, "transfers-per-ns", &obj);
5635 	INSIST(result == ISC_R_SUCCESS);
5636 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
5637 
5638 	obj = NULL;
5639 	result = ns_config_get(maps, "serial-query-rate", &obj);
5640 	INSIST(result == ISC_R_SUCCESS);
5641 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
5642 
5643 	/*
5644 	 * Determine which port to use for listening for incoming connections.
5645 	 */
5646 	if (ns_g_port != 0)
5647 		listen_port = ns_g_port;
5648 	else
5649 		CHECKM(ns_config_getport(config, &listen_port), "port");
5650 
5651 	/*
5652 	 * Determing the default DSCP code point.
5653 	 */
5654 	CHECKM(ns_config_getdscp(config, &ns_g_dscp), "dscp");
5655 
5656 	/*
5657 	 * Find the listen queue depth.
5658 	 */
5659 	obj = NULL;
5660 	result = ns_config_get(maps, "tcp-listen-queue", &obj);
5661 	INSIST(result == ISC_R_SUCCESS);
5662 	ns_g_listen = cfg_obj_asuint32(obj);
5663 	if ((ns_g_listen > 0) && (ns_g_listen < 10))
5664 		ns_g_listen = 10;
5665 
5666 	/*
5667 	 * Configure the interface manager according to the "listen-on"
5668 	 * statement.
5669 	 */
5670 	{
5671 		const cfg_obj_t *clistenon = NULL;
5672 		ns_listenlist_t *listenon = NULL;
5673 
5674 		clistenon = NULL;
5675 		/*
5676 		 * Even though listen-on is present in the default
5677 		 * configuration, we can't use it here, since it isn't
5678 		 * used if we're in lwresd mode.  This way is easier.
5679 		 */
5680 		if (options != NULL)
5681 			(void)cfg_map_get(options, "listen-on", &clistenon);
5682 		if (clistenon != NULL) {
5683 			/* check return code? */
5684 			(void)ns_listenlist_fromconfig(clistenon, config,
5685 						       ns_g_aclconfctx,
5686 						       ns_g_mctx, AF_INET,
5687 						       &listenon);
5688 		} else if (!ns_g_lwresdonly) {
5689 			/*
5690 			 * Not specified, use default.
5691 			 */
5692 			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
5693 						    -1, ISC_TRUE, &listenon));
5694 		}
5695 		if (listenon != NULL) {
5696 			ns_interfacemgr_setlistenon4(server->interfacemgr,
5697 						     listenon);
5698 			ns_listenlist_detach(&listenon);
5699 		}
5700 	}
5701 	/*
5702 	 * Ditto for IPv6.
5703 	 */
5704 	{
5705 		const cfg_obj_t *clistenon = NULL;
5706 		ns_listenlist_t *listenon = NULL;
5707 
5708 		if (options != NULL)
5709 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
5710 		if (clistenon != NULL) {
5711 			/* check return code? */
5712 			(void)ns_listenlist_fromconfig(clistenon, config,
5713 						       ns_g_aclconfctx,
5714 						       ns_g_mctx, AF_INET6,
5715 						       &listenon);
5716 		} else if (!ns_g_lwresdonly) {
5717 			/*
5718 			 * Not specified, use default.
5719 			 */
5720 			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
5721 						    -1, ISC_TRUE, &listenon));
5722 		}
5723 		if (listenon != NULL) {
5724 			ns_interfacemgr_setlistenon6(server->interfacemgr,
5725 						     listenon);
5726 			ns_listenlist_detach(&listenon);
5727 		}
5728 	}
5729 
5730 	/*
5731 	 * Rescan the interface list to pick up changes in the
5732 	 * listen-on option.  It's important that we do this before we try
5733 	 * to configure the query source, since the dispatcher we use might
5734 	 * be shared with an interface.
5735 	 */
5736 	scan_interfaces(server, ISC_TRUE);
5737 
5738 	/*
5739 	 * Arrange for further interface scanning to occur periodically
5740 	 * as specified by the "interface-interval" option.
5741 	 */
5742 	obj = NULL;
5743 	result = ns_config_get(maps, "interface-interval", &obj);
5744 	INSIST(result == ISC_R_SUCCESS);
5745 	interface_interval = cfg_obj_asuint32(obj) * 60;
5746 	if (interface_interval == 0) {
5747 		CHECK(isc_timer_reset(server->interface_timer,
5748 				      isc_timertype_inactive,
5749 				      NULL, NULL, ISC_TRUE));
5750 	} else if (server->interface_interval != interface_interval) {
5751 		isc_interval_set(&interval, interface_interval, 0);
5752 		CHECK(isc_timer_reset(server->interface_timer,
5753 				      isc_timertype_ticker,
5754 				      NULL, &interval, ISC_FALSE));
5755 	}
5756 	server->interface_interval = interface_interval;
5757 
5758 	/*
5759 	 * Enable automatic interface scans.
5760 	 */
5761 	obj = NULL;
5762 	result = ns_config_get(maps, "automatic-interface-scan", &obj);
5763 	INSIST(result == ISC_R_SUCCESS);
5764 	server->interface_auto = cfg_obj_asboolean(obj);
5765 
5766 	/*
5767 	 * Configure the dialup heartbeat timer.
5768 	 */
5769 	obj = NULL;
5770 	result = ns_config_get(maps, "heartbeat-interval", &obj);
5771 	INSIST(result == ISC_R_SUCCESS);
5772 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
5773 	if (heartbeat_interval == 0) {
5774 		CHECK(isc_timer_reset(server->heartbeat_timer,
5775 				      isc_timertype_inactive,
5776 				      NULL, NULL, ISC_TRUE));
5777 	} else if (server->heartbeat_interval != heartbeat_interval) {
5778 		isc_interval_set(&interval, heartbeat_interval, 0);
5779 		CHECK(isc_timer_reset(server->heartbeat_timer,
5780 				      isc_timertype_ticker,
5781 				      NULL, &interval, ISC_FALSE));
5782 	}
5783 	server->heartbeat_interval = heartbeat_interval;
5784 
5785 	isc_interval_set(&interval, 1200, 0);
5786 	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
5787 			      &interval, ISC_FALSE));
5788 
5789 	/*
5790 	 * Write the PID file.
5791 	 */
5792 	obj = NULL;
5793 	if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
5794 		if (cfg_obj_isvoid(obj))
5795 			ns_os_writepidfile(NULL, first_time);
5796 		else
5797 			ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
5798 	else if (ns_g_lwresdonly)
5799 		ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
5800 	else
5801 		ns_os_writepidfile(ns_g_defaultpidfile, first_time);
5802 
5803 	/*
5804 	 * Configure the server-wide session key.  This must be done before
5805 	 * configure views because zone configuration may need to know
5806 	 * session-keyname.
5807 	 *
5808 	 * Failure of session key generation isn't fatal at this time; if it
5809 	 * turns out that a session key is really needed but doesn't exist,
5810 	 * we'll treat it as a fatal error then.
5811 	 */
5812 	(void)configure_session_key(maps, server, ns_g_mctx);
5813 
5814 	views = NULL;
5815 	(void)cfg_map_get(config, "view", &views);
5816 
5817 	/*
5818 	 * Create the views and count all the configured zones in
5819 	 * order to correctly size the zone manager's task table.
5820 	 * (We only count zones for configured views; the built-in
5821 	 * "bind" view can be ignored as it only adds a negligible
5822 	 * number of zones.)
5823 	 *
5824 	 * If we're allowing new zones, we need to be able to find the
5825 	 * new zone file and count those as well.  So we setup the new
5826 	 * zone configuration context, but otherwise view configuration
5827 	 * waits until after the zone manager's task list has been sized.
5828 	 */
5829 	for (element = cfg_list_first(views);
5830 	     element != NULL;
5831 	     element = cfg_list_next(element))
5832 	{
5833 		cfg_obj_t *vconfig = cfg_listelt_value(element);
5834 		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
5835 		view = NULL;
5836 
5837 		CHECK(create_view(vconfig, &viewlist, &view));
5838 		INSIST(view != NULL);
5839 
5840 		num_zones += count_zones(voptions);
5841 		CHECK(setup_newzones(view, config, vconfig, conf_parser,
5842 				     ns_g_aclconfctx));
5843 
5844 		nzctx = view->new_zone_config;
5845 		if (nzctx != NULL && nzctx->nzconfig != NULL)
5846 			num_zones += count_zones(nzctx->nzconfig);
5847 
5848 		dns_view_detach(&view);
5849 	}
5850 
5851 	/*
5852 	 * If there were no explicit views then we do the default
5853 	 * view here.
5854 	 */
5855 	if (views == NULL) {
5856 		CHECK(create_view(NULL, &viewlist, &view));
5857 		INSIST(view != NULL);
5858 
5859 		num_zones = count_zones(config);
5860 
5861 		CHECK(setup_newzones(view, config, NULL,  conf_parser,
5862 				     ns_g_aclconfctx));
5863 
5864 		nzctx = view->new_zone_config;
5865 		if (nzctx != NULL && nzctx->nzconfig != NULL)
5866 			num_zones += count_zones(nzctx->nzconfig);
5867 
5868 		dns_view_detach(&view);
5869 	}
5870 
5871 	/*
5872 	 * Zones have been counted; set the zone manager task pool size.
5873 	 */
5874 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5875 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5876 		      "sizing zone task pool based on %d zones", num_zones);
5877 	CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
5878 
5879 	/*
5880 	 * Configure and freeze all explicit views.  Explicit
5881 	 * views that have zones were already created at parsing
5882 	 * time, but views with no zones must be created here.
5883 	 */
5884 	for (element = cfg_list_first(views);
5885 	     element != NULL;
5886 	     element = cfg_list_next(element))
5887 	{
5888 		cfg_obj_t *vconfig = cfg_listelt_value(element);
5889 
5890 		view = NULL;
5891 		CHECK(find_view(vconfig, &viewlist, &view));
5892 		CHECK(configure_view(view, &viewlist, config, vconfig,
5893 				     &cachelist, bindkeys, ns_g_mctx,
5894 				     ns_g_aclconfctx, ISC_TRUE));
5895 		dns_view_freeze(view);
5896 		dns_view_detach(&view);
5897 	}
5898 
5899 	/*
5900 	 * Make sure we have a default view if and only if there
5901 	 * were no explicit views.
5902 	 */
5903 	if (views == NULL) {
5904 		view = NULL;
5905 		CHECK(find_view(NULL, &viewlist, &view));
5906 		CHECK(configure_view(view, &viewlist, config, NULL,
5907 				     &cachelist, bindkeys,
5908 				     ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
5909 		dns_view_freeze(view);
5910 		dns_view_detach(&view);
5911 	}
5912 
5913 	/*
5914 	 * Create (or recreate) the built-in views.
5915 	 */
5916 	builtin_views = NULL;
5917 	RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
5918 				  &builtin_views) == ISC_R_SUCCESS);
5919 	for (element = cfg_list_first(builtin_views);
5920 	     element != NULL;
5921 	     element = cfg_list_next(element))
5922 	{
5923 		cfg_obj_t *vconfig = cfg_listelt_value(element);
5924 
5925 		CHECK(create_view(vconfig, &builtin_viewlist, &view));
5926 		CHECK(configure_view(view, &viewlist, config, vconfig,
5927 				     &cachelist, bindkeys,
5928 				     ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
5929 		dns_view_freeze(view);
5930 		dns_view_detach(&view);
5931 		view = NULL;
5932 	}
5933 
5934 	/* Now combine the two viewlists into one */
5935 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
5936 
5937 	/* Swap our new view list with the production one. */
5938 	tmpviewlist = server->viewlist;
5939 	server->viewlist = viewlist;
5940 	viewlist = tmpviewlist;
5941 
5942 	/* Make the view list available to each of the views */
5943 	view = ISC_LIST_HEAD(server->viewlist);
5944 	while (view != NULL) {
5945 		view->viewlist = &server->viewlist;
5946 		view = ISC_LIST_NEXT(view, link);
5947 	}
5948 
5949 	/* Swap our new cache list with the production one. */
5950 	tmpcachelist = server->cachelist;
5951 	server->cachelist = cachelist;
5952 	cachelist = tmpcachelist;
5953 
5954 	/* Load the TKEY information from the configuration. */
5955 	if (options != NULL) {
5956 		dns_tkeyctx_t *t = NULL;
5957 		CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
5958 					     &t),
5959 		       "configuring TKEY");
5960 		if (server->tkeyctx != NULL)
5961 			dns_tkeyctx_destroy(&server->tkeyctx);
5962 		server->tkeyctx = t;
5963 	}
5964 
5965 	/*
5966 	 * Bind the control port(s).
5967 	 */
5968 	CHECKM(ns_controls_configure(ns_g_server->controls, config,
5969 				     ns_g_aclconfctx),
5970 	       "binding control channel(s)");
5971 
5972 	/*
5973 	 * Bind the lwresd port(s).
5974 	 */
5975 	CHECKM(ns_lwresd_configure(ns_g_mctx, config),
5976 	       "binding lightweight resolver ports");
5977 
5978 	/*
5979 	 * Open the source of entropy.
5980 	 */
5981 	if (first_time) {
5982 		obj = NULL;
5983 		result = ns_config_get(maps, "random-device", &obj);
5984 		if (result != ISC_R_SUCCESS) {
5985 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5986 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5987 				      "no source of entropy found");
5988 		} else {
5989 			const char *randomdev = cfg_obj_asstring(obj);
5990 			result = isc_entropy_createfilesource(ns_g_entropy,
5991 							      randomdev);
5992 			if (result != ISC_R_SUCCESS)
5993 				isc_log_write(ns_g_lctx,
5994 					      NS_LOGCATEGORY_GENERAL,
5995 					      NS_LOGMODULE_SERVER,
5996 					      ISC_LOG_INFO,
5997 					      "could not open entropy source "
5998 					      "%s: %s",
5999 					      randomdev,
6000 					      isc_result_totext(result));
6001 #ifdef PATH_RANDOMDEV
6002 			if (ns_g_fallbackentropy != NULL) {
6003 				if (result != ISC_R_SUCCESS) {
6004 					isc_log_write(ns_g_lctx,
6005 						      NS_LOGCATEGORY_GENERAL,
6006 						      NS_LOGMODULE_SERVER,
6007 						      ISC_LOG_INFO,
6008 						      "using pre-chroot entropy source "
6009 						      "%s",
6010 						      PATH_RANDOMDEV);
6011 					isc_entropy_detach(&ns_g_entropy);
6012 					isc_entropy_attach(ns_g_fallbackentropy,
6013 							   &ns_g_entropy);
6014 				}
6015 				isc_entropy_detach(&ns_g_fallbackentropy);
6016 			}
6017 #endif
6018 		}
6019 	}
6020 
6021 	/*
6022 	 * Relinquish root privileges.
6023 	 */
6024 	if (first_time)
6025 		ns_os_changeuser();
6026 
6027 #if 0
6028 	/*
6029 	 * Check that the working directory is writable.
6030 	 */
6031 	if (access(".", W_OK) != 0) {
6032 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6033 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6034 			      "the working directory is not writable");
6035 	}
6036 #endif
6037 
6038 	/*
6039 	 * Configure the logging system.
6040 	 *
6041 	 * Do this after changing UID to make sure that any log
6042 	 * files specified in named.conf get created by the
6043 	 * unprivileged user, not root.
6044 	 */
6045 	if (ns_g_logstderr) {
6046 		const cfg_obj_t *logobj = NULL;
6047 
6048 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6049 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6050 			      "not using config file logging "
6051 			      "statement for logging due to "
6052 			      "-g option");
6053 
6054 		(void)cfg_map_get(config, "logging", &logobj);
6055 		if (logobj != NULL) {
6056 			result = ns_log_configure(NULL, logobj);
6057 			if (result != ISC_R_SUCCESS) {
6058 				isc_log_write(ns_g_lctx,
6059 					      NS_LOGCATEGORY_GENERAL,
6060 					      NS_LOGMODULE_SERVER,
6061 					      ISC_LOG_ERROR,
6062 					      "checking logging configuration "
6063 					      "failed: %s",
6064 					      isc_result_totext(result));
6065 				goto cleanup;
6066 			}
6067 		}
6068 	} else {
6069 		const cfg_obj_t *logobj = NULL;
6070 
6071 		CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
6072 		       "creating new logging configuration");
6073 
6074 		logobj = NULL;
6075 		(void)cfg_map_get(config, "logging", &logobj);
6076 		if (logobj != NULL) {
6077 			CHECKM(ns_log_configure(logc, logobj),
6078 			       "configuring logging");
6079 		} else {
6080 			CHECKM(ns_log_setdefaultchannels(logc),
6081 			       "setting up default logging channels");
6082 			CHECKM(ns_log_setunmatchedcategory(logc),
6083 			       "setting up default 'category unmatched'");
6084 			CHECKM(ns_log_setdefaultcategory(logc),
6085 			       "setting up default 'category default'");
6086 		}
6087 
6088 		CHECKM(isc_logconfig_use(ns_g_lctx, logc),
6089 		       "installing logging configuration");
6090 		logc = NULL;
6091 
6092 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6093 			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
6094 			      "now using logging configuration from "
6095 			      "config file");
6096 	}
6097 
6098 	/*
6099 	 * Set the default value of the query logging flag depending
6100 	 * whether a "queries" category has been defined.  This is
6101 	 * a disgusting hack, but we need to do this for BIND 8
6102 	 * compatibility.
6103 	 */
6104 	if (first_time) {
6105 		const cfg_obj_t *logobj = NULL;
6106 		const cfg_obj_t *categories = NULL;
6107 
6108 		obj = NULL;
6109 		if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
6110 			server->log_queries = cfg_obj_asboolean(obj);
6111 		} else {
6112 
6113 			(void)cfg_map_get(config, "logging", &logobj);
6114 			if (logobj != NULL)
6115 				(void)cfg_map_get(logobj, "category",
6116 						  &categories);
6117 			if (categories != NULL) {
6118 				for (element = cfg_list_first(categories);
6119 				     element != NULL;
6120 				     element = cfg_list_next(element))
6121 				{
6122 					const cfg_obj_t *catobj;
6123 					const char *str;
6124 
6125 					obj = cfg_listelt_value(element);
6126 					catobj = cfg_tuple_get(obj, "name");
6127 					str = cfg_obj_asstring(catobj);
6128 					if (strcasecmp(str, "queries") == 0)
6129 						server->log_queries = ISC_TRUE;
6130 				}
6131 			}
6132 		}
6133 	}
6134 
6135 
6136 	obj = NULL;
6137 	if (options != NULL &&
6138 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
6139 		ns_g_memstatistics = cfg_obj_asboolean(obj);
6140 	else
6141 		ns_g_memstatistics =
6142 			ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
6143 
6144 	obj = NULL;
6145 	if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
6146 		ns_main_setmemstats(cfg_obj_asstring(obj));
6147 	else if (ns_g_memstatistics)
6148 		ns_main_setmemstats("named.memstats");
6149 	else
6150 		ns_main_setmemstats(NULL);
6151 
6152 	obj = NULL;
6153 	result = ns_config_get(maps, "statistics-file", &obj);
6154 	INSIST(result == ISC_R_SUCCESS);
6155 	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
6156 	       "strdup");
6157 
6158 	obj = NULL;
6159 	result = ns_config_get(maps, "dump-file", &obj);
6160 	INSIST(result == ISC_R_SUCCESS);
6161 	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
6162 	       "strdup");
6163 
6164 	obj = NULL;
6165 	result = ns_config_get(maps, "secroots-file", &obj);
6166 	INSIST(result == ISC_R_SUCCESS);
6167 	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
6168 	       "strdup");
6169 
6170 	obj = NULL;
6171 	result = ns_config_get(maps, "recursing-file", &obj);
6172 	INSIST(result == ISC_R_SUCCESS);
6173 	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
6174 	       "strdup");
6175 
6176 	obj = NULL;
6177 	result = ns_config_get(maps, "version", &obj);
6178 	if (result == ISC_R_SUCCESS) {
6179 		CHECKM(setoptstring(server, &server->version, obj), "strdup");
6180 		server->version_set = ISC_TRUE;
6181 	} else {
6182 		server->version_set = ISC_FALSE;
6183 	}
6184 
6185 	obj = NULL;
6186 	result = ns_config_get(maps, "hostname", &obj);
6187 	if (result == ISC_R_SUCCESS) {
6188 		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
6189 		server->hostname_set = ISC_TRUE;
6190 	} else {
6191 		server->hostname_set = ISC_FALSE;
6192 	}
6193 
6194 	obj = NULL;
6195 	result = ns_config_get(maps, "server-id", &obj);
6196 	server->server_usehostname = ISC_FALSE;
6197 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
6198 		/* The parser translates "hostname" to ISC_TRUE */
6199 		server->server_usehostname = cfg_obj_asboolean(obj);
6200 		result = setstring(server, &server->server_id, NULL);
6201 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
6202 	} else if (result == ISC_R_SUCCESS) {
6203 		/* Found a quoted string */
6204 		CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
6205 	} else {
6206 		result = setstring(server, &server->server_id, NULL);
6207 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
6208 	}
6209 
6210 	obj = NULL;
6211 	result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
6212 	if (result == ISC_R_SUCCESS) {
6213 		server->flushonshutdown = cfg_obj_asboolean(obj);
6214 	} else {
6215 		server->flushonshutdown = ISC_FALSE;
6216 	}
6217 
6218 #ifdef ISC_PLATFORM_USESIT
6219 	obj = NULL;
6220 	result = ns_config_get(maps, "sit-secret", &obj);
6221 	if (result == ISC_R_SUCCESS) {
6222 		isc_buffer_t b;
6223 
6224 		memset(server->secret, 0, sizeof(server->secret));
6225 		isc_buffer_init(&b, server->secret, sizeof(server->secret));
6226 		result = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
6227 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
6228 			goto cleanup;
6229 #ifdef AES_SIT
6230 		if (isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH)
6231 			CHECKM(ISC_R_RANGE,
6232 			       "AES sit-secret must be on 128 bits");
6233 #endif
6234 #ifdef HMAC_SHA1_SIT
6235 		if (isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH)
6236 			CHECKM(ISC_R_RANGE,
6237 			       "SHA1 sit-secret must be on 160 bits");
6238 #endif
6239 #ifdef HMAC_SHA256_SIT
6240 		if (isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH)
6241 			CHECKM(ISC_R_RANGE,
6242 			       "SHA256 sit-secret must be on 256 bits");
6243 #endif
6244 	} else {
6245 		result = isc_entropy_getdata(ns_g_entropy,
6246 					     server->secret,
6247 					     sizeof(server->secret),
6248 					     NULL,
6249 					     0);
6250 		if (result != ISC_R_SUCCESS)
6251 			goto cleanup;
6252 	}
6253 #endif
6254 
6255 	result = ISC_R_SUCCESS;
6256 
6257  cleanup:
6258 	if (logc != NULL)
6259 		isc_logconfig_destroy(&logc);
6260 
6261 	if (v4portset != NULL)
6262 		isc_portset_destroy(ns_g_mctx, &v4portset);
6263 
6264 	if (v6portset != NULL)
6265 		isc_portset_destroy(ns_g_mctx, &v6portset);
6266 
6267 	if (conf_parser != NULL) {
6268 		if (config != NULL)
6269 			cfg_obj_destroy(conf_parser, &config);
6270 		cfg_parser_destroy(&conf_parser);
6271 	}
6272 
6273 	if (bindkeys_parser != NULL) {
6274 		if (bindkeys != NULL)
6275 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
6276 		cfg_parser_destroy(&bindkeys_parser);
6277 	}
6278 
6279 	if (view != NULL)
6280 		dns_view_detach(&view);
6281 
6282 	/*
6283 	 * This cleans up either the old production view list
6284 	 * or our temporary list depending on whether they
6285 	 * were swapped above or not.
6286 	 */
6287 	for (view = ISC_LIST_HEAD(viewlist);
6288 	     view != NULL;
6289 	     view = view_next) {
6290 		view_next = ISC_LIST_NEXT(view, link);
6291 		ISC_LIST_UNLINK(viewlist, view, link);
6292 		if (result == ISC_R_SUCCESS &&
6293 		    strcmp(view->name, "_bind") != 0)
6294 			(void)dns_zt_apply(view->zonetable, ISC_FALSE,
6295 					   removed, view);
6296 		dns_view_detach(&view);
6297 	}
6298 
6299 	/* Same cleanup for cache list. */
6300 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
6301 		ISC_LIST_UNLINK(cachelist, nsc, link);
6302 		dns_cache_detach(&nsc->cache);
6303 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
6304 	}
6305 
6306 	/*
6307 	 * Adjust the listening interfaces in accordance with the source
6308 	 * addresses specified in views and zones.
6309 	 */
6310 	if (isc_net_probeipv6() == ISC_R_SUCCESS)
6311 		adjust_interfaces(server, ns_g_mctx);
6312 
6313 	/*
6314 	 * Record the time of most recent configuration
6315 	 */
6316 	tresult = isc_time_now(&ns_g_configtime);
6317 	if (tresult != ISC_R_SUCCESS)
6318 		ns_main_earlyfatal("isc_time_now() failed: %s",
6319 				   isc_result_totext(result));
6320 
6321 	/* Relinquish exclusive access to configuration data. */
6322 	if (exclusive)
6323 		isc_task_endexclusive(server->task);
6324 
6325 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6326 		      ISC_LOG_DEBUG(1), "load_configuration: %s",
6327 		      isc_result_totext(result));
6328 
6329 	return (result);
6330 }
6331 
6332 static isc_result_t
6333 view_loaded(void *arg) {
6334 	isc_result_t result;
6335 	ns_zoneload_t *zl = (ns_zoneload_t *) arg;
6336 	ns_server_t *server = zl->server;
6337 	unsigned int refs;
6338 
6339 
6340 	/*
6341 	 * Force zone maintenance.  Do this after loading
6342 	 * so that we know when we need to force AXFR of
6343 	 * slave zones whose master files are missing.
6344 	 *
6345 	 * We use the zoneload reference counter to let us
6346 	 * know when all views are finished.
6347 	 */
6348 	isc_refcount_decrement(&zl->refs, &refs);
6349 	if (refs != 0)
6350 		return (ISC_R_SUCCESS);
6351 
6352 	isc_refcount_destroy(&zl->refs);
6353 	isc_mem_put(server->mctx, zl, sizeof (*zl));
6354 
6355 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6356 		      ISC_LOG_NOTICE, "all zones loaded");
6357 	CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
6358 		   "forcing zone maintenance");
6359 
6360 	ns_os_started();
6361 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6362 		      ISC_LOG_NOTICE, "running");
6363 
6364 	return (ISC_R_SUCCESS);
6365 }
6366 
6367 static isc_result_t
6368 load_zones(ns_server_t *server, isc_boolean_t init) {
6369 	isc_result_t result;
6370 	dns_view_t *view;
6371 	ns_zoneload_t *zl;
6372 	unsigned int refs = 0;
6373 
6374 	zl = isc_mem_get(server->mctx, sizeof (*zl));
6375 	if (zl == NULL)
6376 		return (ISC_R_NOMEMORY);
6377 	zl->server = server;
6378 
6379 	result = isc_task_beginexclusive(server->task);
6380 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6381 
6382 	isc_refcount_init(&zl->refs, 1);
6383 
6384 	/*
6385 	 * Schedule zones to be loaded from disk.
6386 	 */
6387 	for (view = ISC_LIST_HEAD(server->viewlist);
6388 	     view != NULL;
6389 	     view = ISC_LIST_NEXT(view, link))
6390 	{
6391 		if (view->managed_keys != NULL) {
6392 			result = dns_zone_load(view->managed_keys);
6393 			if (result != ISC_R_SUCCESS &&
6394 			    result != DNS_R_UPTODATE &&
6395 			    result != DNS_R_CONTINUE)
6396 				goto cleanup;
6397 		}
6398 		if (view->redirect != NULL) {
6399 			result = dns_zone_load(view->redirect);
6400 			if (result != ISC_R_SUCCESS &&
6401 			    result != DNS_R_UPTODATE &&
6402 			    result != DNS_R_CONTINUE)
6403 				goto cleanup;
6404 		}
6405 
6406 		/*
6407 		 * 'dns_view_asyncload' calls view_loaded if there are no
6408 		 * zones.
6409 		 */
6410 		isc_refcount_increment(&zl->refs, NULL);
6411 		CHECK(dns_view_asyncload(view, view_loaded, zl));
6412 	}
6413 
6414  cleanup:
6415 	isc_refcount_decrement(&zl->refs, &refs);
6416 	if (refs == 0) {
6417 		isc_refcount_destroy(&zl->refs);
6418 		isc_mem_put(server->mctx, zl, sizeof (*zl));
6419 	} else if (init) {
6420 		/*
6421 		 * Place the task manager into privileged mode.  This
6422 		 * ensures that after we leave task-exclusive mode, no
6423 		 * other tasks will be able to run except for the ones
6424 		 * that are loading zones. (This should only be done during
6425 		 * the initial server setup; it isn't necessary during
6426 		 * a reload.)
6427 		 */
6428 		isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged);
6429 	}
6430 
6431 	isc_task_endexclusive(server->task);
6432 	return (result);
6433 }
6434 
6435 static isc_result_t
6436 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
6437 	isc_result_t result;
6438 	dns_view_t *view;
6439 
6440 	result = isc_task_beginexclusive(server->task);
6441 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6442 
6443 	/*
6444 	 * Load zone data from disk.
6445 	 */
6446 	for (view = ISC_LIST_HEAD(server->viewlist);
6447 	     view != NULL;
6448 	     view = ISC_LIST_NEXT(view, link))
6449 	{
6450 		CHECK(dns_view_loadnew(view, stop));
6451 
6452 		/* Load managed-keys data */
6453 		if (view->managed_keys != NULL)
6454 			CHECK(dns_zone_loadnew(view->managed_keys));
6455 		if (view->redirect != NULL)
6456 			CHECK(dns_zone_loadnew(view->redirect));
6457 	}
6458 
6459 	/*
6460 	 * Resume zone XFRs.
6461 	 */
6462 	dns_zonemgr_resumexfrs(server->zonemgr);
6463  cleanup:
6464 	isc_task_endexclusive(server->task);
6465 	return (result);
6466 }
6467 
6468 static void
6469 run_server(isc_task_t *task, isc_event_t *event) {
6470 	isc_result_t result;
6471 	ns_server_t *server = (ns_server_t *)event->ev_arg;
6472 
6473 	INSIST(task == server->task);
6474 
6475 	isc_event_free(&event);
6476 
6477 	CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
6478 					  &ns_g_dispatchmgr),
6479 		   "creating dispatch manager");
6480 
6481 	dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
6482 
6483 	CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
6484 					  ns_g_socketmgr, ns_g_dispatchmgr,
6485 					  server->task, &server->interfacemgr),
6486 		   "creating interface manager");
6487 
6488 	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
6489 				    NULL, NULL, server->task,
6490 				    interface_timer_tick,
6491 				    server, &server->interface_timer),
6492 		   "creating interface timer");
6493 
6494 	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
6495 				    NULL, NULL, server->task,
6496 				    heartbeat_timer_tick,
6497 				    server, &server->heartbeat_timer),
6498 		   "creating heartbeat timer");
6499 
6500 	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
6501 				    NULL, NULL, server->task, pps_timer_tick,
6502 				    server, &server->pps_timer),
6503 		   "creating pps timer");
6504 
6505 	CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
6506 		   "creating default configuration parser");
6507 
6508 	if (ns_g_lwresdonly)
6509 		CHECKFATAL(load_configuration(lwresd_g_conffile, server,
6510 					      ISC_TRUE),
6511 			   "loading configuration");
6512 	else
6513 		CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
6514 			   "loading configuration");
6515 
6516 	isc_hash_init();
6517 
6518 	CHECKFATAL(load_zones(server, ISC_TRUE), "loading zones");
6519 }
6520 
6521 void
6522 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
6523 
6524 	REQUIRE(NS_SERVER_VALID(server));
6525 
6526 	server->flushonshutdown = flush;
6527 }
6528 
6529 static void
6530 shutdown_server(isc_task_t *task, isc_event_t *event) {
6531 	isc_result_t result;
6532 	dns_view_t *view, *view_next;
6533 	ns_server_t *server = (ns_server_t *)event->ev_arg;
6534 	isc_boolean_t flush = server->flushonshutdown;
6535 	ns_cache_t *nsc;
6536 
6537 	UNUSED(task);
6538 	INSIST(task == server->task);
6539 
6540 	result = isc_task_beginexclusive(server->task);
6541 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6542 
6543 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6544 		      ISC_LOG_INFO, "shutting down%s",
6545 		      flush ? ": flushing changes" : "");
6546 
6547 	ns_statschannels_shutdown(server);
6548 	ns_controls_shutdown(server->controls);
6549 	end_reserved_dispatches(server, ISC_TRUE);
6550 	cleanup_session_key(server, server->mctx);
6551 
6552 	if (ns_g_aclconfctx != NULL)
6553 		cfg_aclconfctx_detach(&ns_g_aclconfctx);
6554 
6555 	cfg_obj_destroy(ns_g_parser, &ns_g_config);
6556 	cfg_parser_destroy(&ns_g_parser);
6557 
6558 	for (view = ISC_LIST_HEAD(server->viewlist);
6559 	     view != NULL;
6560 	     view = view_next) {
6561 		view_next = ISC_LIST_NEXT(view, link);
6562 		ISC_LIST_UNLINK(server->viewlist, view, link);
6563 		if (flush)
6564 			dns_view_flushanddetach(&view);
6565 		else
6566 			dns_view_detach(&view);
6567 	}
6568 
6569 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
6570 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
6571 		dns_cache_detach(&nsc->cache);
6572 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
6573 	}
6574 
6575 	isc_timer_detach(&server->interface_timer);
6576 	isc_timer_detach(&server->heartbeat_timer);
6577 	isc_timer_detach(&server->pps_timer);
6578 
6579 	ns_interfacemgr_shutdown(server->interfacemgr);
6580 	ns_interfacemgr_detach(&server->interfacemgr);
6581 
6582 	dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
6583 
6584 	dns_zonemgr_shutdown(server->zonemgr);
6585 
6586 	if (ns_g_sessionkey != NULL) {
6587 		dns_tsigkey_detach(&ns_g_sessionkey);
6588 		dns_name_free(&ns_g_sessionkeyname, server->mctx);
6589 	}
6590 
6591 	if (server->blackholeacl != NULL)
6592 		dns_acl_detach(&server->blackholeacl);
6593 
6594 #ifdef HAVE_GEOIP
6595 	dns_geoip_shutdown();
6596 #endif
6597 
6598 	dns_db_detach(&server->in_roothints);
6599 
6600 	isc_task_endexclusive(server->task);
6601 
6602 	isc_task_detach(&server->task);
6603 
6604 	isc_event_free(&event);
6605 }
6606 
6607 void
6608 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
6609 	isc_result_t result;
6610 	ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
6611 
6612 	if (server == NULL)
6613 		fatal("allocating server object", ISC_R_NOMEMORY);
6614 
6615 	server->mctx = mctx;
6616 	server->task = NULL;
6617 
6618 	/* Initialize configuration data with default values. */
6619 	result = isc_quota_init(&server->xfroutquota, 10);
6620 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6621 	result = isc_quota_init(&server->tcpquota, 10);
6622 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6623 	result = isc_quota_init(&server->recursionquota, 100);
6624 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6625 
6626 
6627 	result = dns_aclenv_init(mctx, &server->aclenv);
6628 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6629 
6630 #ifdef HAVE_GEOIP
6631 	/* Initialize GeoIP before using ACL environment */
6632 	ns_geoip_init();
6633 	server->aclenv.geoip = ns_g_geoip;
6634 #endif
6635 
6636 	/* Initialize server data structures. */
6637 	server->zonemgr = NULL;
6638 	server->interfacemgr = NULL;
6639 	ISC_LIST_INIT(server->viewlist);
6640 	server->in_roothints = NULL;
6641 	server->blackholeacl = NULL;
6642 
6643 	/* Must be first. */
6644 	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
6645 				 ns_g_engine, ISC_ENTROPY_GOODONLY),
6646 		   "initializing DST");
6647 
6648 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
6649 				     &server->in_roothints),
6650 		   "setting up root hints");
6651 
6652 	CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
6653 		   "initializing reload event lock");
6654 	server->reload_event =
6655 		isc_event_allocate(ns_g_mctx, server,
6656 				   NS_EVENT_RELOAD,
6657 				   ns_server_reload,
6658 				   server,
6659 				   sizeof(isc_event_t));
6660 	CHECKFATAL(server->reload_event == NULL ?
6661 		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
6662 		   "allocating reload event");
6663 
6664 	server->tkeyctx = NULL;
6665 	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
6666 				      &server->tkeyctx),
6667 		   "creating TKEY context");
6668 
6669 	/*
6670 	 * Setup the server task, which is responsible for coordinating
6671 	 * startup and shutdown of the server, as well as all exclusive
6672 	 * tasks.
6673 	 */
6674 	CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
6675 		   "creating server task");
6676 	isc_task_setname(server->task, "server", server);
6677 	isc_taskmgr_setexcltask(ns_g_taskmgr, server->task);
6678 	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
6679 		   "isc_task_onshutdown");
6680 	CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
6681 		   "isc_app_onrun");
6682 
6683 	server->interface_timer = NULL;
6684 	server->heartbeat_timer = NULL;
6685 	server->pps_timer = NULL;
6686 
6687 	server->interface_interval = 0;
6688 	server->heartbeat_interval = 0;
6689 
6690 	CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
6691 				      ns_g_socketmgr, &server->zonemgr),
6692 		   "dns_zonemgr_create");
6693 	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
6694 		   "dns_zonemgr_setsize");
6695 
6696 	server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
6697 	CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6698 		   "isc_mem_strdup");
6699 	server->nsstats = NULL;
6700 	server->rcvquerystats = NULL;
6701 	server->opcodestats = NULL;
6702 	server->zonestats = NULL;
6703 	server->resolverstats = NULL;
6704 	server->sockstats = NULL;
6705 	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
6706 				    isc_sockstatscounter_max),
6707 		   "isc_stats_create");
6708 	isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
6709 
6710 	server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys");
6711 	CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
6712 						  ISC_R_SUCCESS,
6713 		   "isc_mem_strdup");
6714 
6715 	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
6716 	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6717 		   "isc_mem_strdup");
6718 
6719 	server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
6720 	CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
6721 						  ISC_R_SUCCESS,
6722 		   "isc_mem_strdup");
6723 
6724 	server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
6725 	CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6726 		   "isc_mem_strdup");
6727 
6728 	server->hostname_set = ISC_FALSE;
6729 	server->hostname = NULL;
6730 	server->version_set = ISC_FALSE;
6731 	server->version = NULL;
6732 	server->server_usehostname = ISC_FALSE;
6733 	server->server_id = NULL;
6734 
6735 	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
6736 				    dns_nsstatscounter_max),
6737 		   "dns_stats_create (server)");
6738 
6739 	CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
6740 					     &server->rcvquerystats),
6741 		   "dns_stats_create (rcvquery)");
6742 
6743 	CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
6744 		   "dns_stats_create (opcode)");
6745 
6746 	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
6747 				    dns_zonestatscounter_max),
6748 		   "dns_stats_create (zone)");
6749 
6750 	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
6751 				    dns_resstatscounter_max),
6752 		   "dns_stats_create (resolver)");
6753 
6754 	server->flushonshutdown = ISC_FALSE;
6755 	server->log_queries = ISC_FALSE;
6756 
6757 	server->controls = NULL;
6758 	CHECKFATAL(ns_controls_create(server, &server->controls),
6759 		   "ns_controls_create");
6760 	server->dispatchgen = 0;
6761 	ISC_LIST_INIT(server->dispatches);
6762 
6763 	ISC_LIST_INIT(server->statschannels);
6764 
6765 	ISC_LIST_INIT(server->cachelist);
6766 
6767 	server->sessionkey = NULL;
6768 	server->session_keyfile = NULL;
6769 	server->session_keyname = NULL;
6770 	server->session_keyalg = DST_ALG_UNKNOWN;
6771 	server->session_keybits = 0;
6772 
6773 	server->magic = NS_SERVER_MAGIC;
6774 	*serverp = server;
6775 }
6776 
6777 void
6778 ns_server_destroy(ns_server_t **serverp) {
6779 	ns_server_t *server = *serverp;
6780 	REQUIRE(NS_SERVER_VALID(server));
6781 
6782 	ns_controls_destroy(&server->controls);
6783 
6784 	isc_stats_detach(&server->nsstats);
6785 	dns_stats_detach(&server->rcvquerystats);
6786 	dns_stats_detach(&server->opcodestats);
6787 	isc_stats_detach(&server->zonestats);
6788 	isc_stats_detach(&server->resolverstats);
6789 	isc_stats_detach(&server->sockstats);
6790 
6791 	isc_mem_free(server->mctx, server->statsfile);
6792 	isc_mem_free(server->mctx, server->bindkeysfile);
6793 	isc_mem_free(server->mctx, server->dumpfile);
6794 	isc_mem_free(server->mctx, server->secrootsfile);
6795 	isc_mem_free(server->mctx, server->recfile);
6796 
6797 	if (server->version != NULL)
6798 		isc_mem_free(server->mctx, server->version);
6799 	if (server->hostname != NULL)
6800 		isc_mem_free(server->mctx, server->hostname);
6801 	if (server->server_id != NULL)
6802 		isc_mem_free(server->mctx, server->server_id);
6803 
6804 	if (server->zonemgr != NULL)
6805 		dns_zonemgr_detach(&server->zonemgr);
6806 
6807 	if (server->tkeyctx != NULL)
6808 		dns_tkeyctx_destroy(&server->tkeyctx);
6809 
6810 	dst_lib_destroy();
6811 
6812 	isc_event_free(&server->reload_event);
6813 
6814 	INSIST(ISC_LIST_EMPTY(server->viewlist));
6815 	INSIST(ISC_LIST_EMPTY(server->cachelist));
6816 
6817 	dns_aclenv_destroy(&server->aclenv);
6818 
6819 	isc_quota_destroy(&server->recursionquota);
6820 	isc_quota_destroy(&server->tcpquota);
6821 	isc_quota_destroy(&server->xfroutquota);
6822 
6823 	server->magic = 0;
6824 	isc_mem_put(server->mctx, server, sizeof(*server));
6825 	*serverp = NULL;
6826 }
6827 
6828 static void
6829 fatal(const char *msg, isc_result_t result) {
6830 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6831 		      ISC_LOG_CRITICAL, "%s: %s", msg,
6832 		      isc_result_totext(result));
6833 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6834 		      ISC_LOG_CRITICAL, "exiting (due to fatal error)");
6835 	exit(1);
6836 }
6837 
6838 static void
6839 start_reserved_dispatches(ns_server_t *server) {
6840 
6841 	REQUIRE(NS_SERVER_VALID(server));
6842 
6843 	server->dispatchgen++;
6844 }
6845 
6846 static void
6847 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
6848 	ns_dispatch_t *dispatch, *nextdispatch;
6849 
6850 	REQUIRE(NS_SERVER_VALID(server));
6851 
6852 	for (dispatch = ISC_LIST_HEAD(server->dispatches);
6853 	     dispatch != NULL;
6854 	     dispatch = nextdispatch) {
6855 		nextdispatch = ISC_LIST_NEXT(dispatch, link);
6856 		if (!all && server->dispatchgen == dispatch-> dispatchgen)
6857 			continue;
6858 		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
6859 		dns_dispatch_detach(&dispatch->dispatch);
6860 		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
6861 	}
6862 }
6863 
6864 void
6865 ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
6866 	ns_dispatch_t *dispatch;
6867 	in_port_t port;
6868 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
6869 	isc_result_t result;
6870 	unsigned int attrs, attrmask;
6871 
6872 	REQUIRE(NS_SERVER_VALID(server));
6873 
6874 	port = isc_sockaddr_getport(addr);
6875 	if (port == 0 || port >= 1024)
6876 		return;
6877 
6878 	for (dispatch = ISC_LIST_HEAD(server->dispatches);
6879 	     dispatch != NULL;
6880 	     dispatch = ISC_LIST_NEXT(dispatch, link)) {
6881 		if (isc_sockaddr_equal(&dispatch->addr, addr))
6882 			break;
6883 	}
6884 	if (dispatch != NULL) {
6885 		dispatch->dispatchgen = server->dispatchgen;
6886 		return;
6887 	}
6888 
6889 	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
6890 	if (dispatch == NULL) {
6891 		result = ISC_R_NOMEMORY;
6892 		goto cleanup;
6893 	}
6894 
6895 	dispatch->addr = *addr;
6896 	dispatch->dispatchgen = server->dispatchgen;
6897 	dispatch->dispatch = NULL;
6898 
6899 	attrs = 0;
6900 	attrs |= DNS_DISPATCHATTR_UDP;
6901 	switch (isc_sockaddr_pf(addr)) {
6902 	case AF_INET:
6903 		attrs |= DNS_DISPATCHATTR_IPV4;
6904 		break;
6905 	case AF_INET6:
6906 		attrs |= DNS_DISPATCHATTR_IPV6;
6907 		break;
6908 	default:
6909 		result = ISC_R_NOTIMPLEMENTED;
6910 		goto cleanup;
6911 	}
6912 	attrmask = 0;
6913 	attrmask |= DNS_DISPATCHATTR_UDP;
6914 	attrmask |= DNS_DISPATCHATTR_TCP;
6915 	attrmask |= DNS_DISPATCHATTR_IPV4;
6916 	attrmask |= DNS_DISPATCHATTR_IPV6;
6917 
6918 	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
6919 				     ns_g_taskmgr, &dispatch->addr, 4096,
6920 				     UDPBUFFERS, 32768, 16411, 16433,
6921 				     attrs, attrmask, &dispatch->dispatch);
6922 	if (result != ISC_R_SUCCESS)
6923 		goto cleanup;
6924 
6925 	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
6926 
6927 	return;
6928 
6929  cleanup:
6930 	if (dispatch != NULL)
6931 		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
6932 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
6933 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6934 		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
6935 		      "unable to create dispatch for reserved port %s: %s",
6936 		      addrbuf, isc_result_totext(result));
6937 }
6938 
6939 
6940 static isc_result_t
6941 loadconfig(ns_server_t *server) {
6942 	isc_result_t result;
6943 	start_reserved_dispatches(server);
6944 	result = load_configuration(ns_g_lwresdonly ?
6945 				    lwresd_g_conffile : ns_g_conffile,
6946 				    server, ISC_FALSE);
6947 	if (result == ISC_R_SUCCESS) {
6948 		end_reserved_dispatches(server, ISC_FALSE);
6949 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6950 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6951 			      "reloading configuration succeeded");
6952 	} else {
6953 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6954 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6955 			      "reloading configuration failed: %s",
6956 			      isc_result_totext(result));
6957 	}
6958 
6959 	return (result);
6960 }
6961 
6962 static isc_result_t
6963 reload(ns_server_t *server) {
6964 	isc_result_t result;
6965 	CHECK(loadconfig(server));
6966 
6967 	result = load_zones(server, ISC_FALSE);
6968 	if (result == ISC_R_SUCCESS)
6969 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6970 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6971 			      "reloading zones succeeded");
6972 	else
6973 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6974 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6975 			      "reloading zones failed: %s",
6976 			      isc_result_totext(result));
6977 
6978  cleanup:
6979 	return (result);
6980 }
6981 
6982 static void
6983 reconfig(ns_server_t *server) {
6984 	isc_result_t result;
6985 	CHECK(loadconfig(server));
6986 
6987 	result = load_new_zones(server, ISC_FALSE);
6988 	if (result == ISC_R_SUCCESS)
6989 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6990 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6991 			      "any newly configured zones are now loaded");
6992 	else
6993 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6994 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6995 			      "loading new zones failed: %s",
6996 			      isc_result_totext(result));
6997 
6998  cleanup: ;
6999 }
7000 
7001 /*
7002  * Handle a reload event (from SIGHUP).
7003  */
7004 static void
7005 ns_server_reload(isc_task_t *task, isc_event_t *event) {
7006 	ns_server_t *server = (ns_server_t *)event->ev_arg;
7007 
7008 	INSIST(task = server->task);
7009 	UNUSED(task);
7010 
7011 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7012 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7013 		      "received SIGHUP signal to reload zones");
7014 	(void)reload(server);
7015 
7016 	LOCK(&server->reload_event_lock);
7017 	INSIST(server->reload_event == NULL);
7018 	server->reload_event = event;
7019 	UNLOCK(&server->reload_event_lock);
7020 }
7021 
7022 void
7023 ns_server_reloadwanted(ns_server_t *server) {
7024 	LOCK(&server->reload_event_lock);
7025 	if (server->reload_event != NULL)
7026 		isc_task_send(server->task, &server->reload_event);
7027 	UNLOCK(&server->reload_event_lock);
7028 }
7029 
7030 void
7031 ns_server_scan_interfaces(ns_server_t *server) {
7032 	isc_result_t result;
7033 
7034 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7035 		      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
7036 		      "automatic interface rescan");
7037 
7038 	result = isc_task_beginexclusive(server->task);
7039 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7040 	scan_interfaces(server, ISC_TRUE);
7041 	isc_task_endexclusive(server->task);
7042 }
7043 
7044 static char *
7045 next_token(char **stringp, const char *delim) {
7046 	char *res;
7047 
7048 	do {
7049 		res = strsep(stringp, delim);
7050 		if (res == NULL)
7051 			break;
7052 	} while (*res == '\0');
7053 	return (res);
7054 }
7055 
7056 /*
7057  * Find the zone specified in the control channel command 'args',
7058  * if any.  If a zone is specified, point '*zonep' at it, otherwise
7059  * set '*zonep' to NULL.
7060  *
7061  * If 'zonetxt' is set, the caller has already pulled a token
7062  * off the command line that is to be used as the zone name.  (This
7063  * is done when it's necessary to check for an optional argument
7064  * before the zone name, as in "rndc sync [-clean] zone".)
7065  */
7066 static isc_result_t
7067 zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
7068 	       dns_zone_t **zonep, const char **zonename,
7069 	       isc_buffer_t *text, isc_boolean_t skip)
7070 {
7071 	char *input, *ptr;
7072 	char *classtxt;
7073 	const char *viewtxt = NULL;
7074 	dns_fixedname_t fname;
7075 	dns_name_t *name;
7076 	isc_result_t result;
7077 	dns_view_t *view = NULL;
7078 	dns_rdataclass_t rdclass;
7079 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
7080 
7081 	REQUIRE(zonep != NULL && *zonep == NULL);
7082 	REQUIRE(zonename == NULL || *zonename == NULL);
7083 
7084 	input = args;
7085 
7086 	if (skip) {
7087 		/* Skip the command name. */
7088 		ptr = next_token(&input, " \t");
7089 		if (ptr == NULL)
7090 			return (ISC_R_UNEXPECTEDEND);
7091 	}
7092 
7093 	/* Look for the zone name. */
7094 	if (zonetxt == NULL)
7095 		zonetxt = next_token(&input, " \t");
7096 	if (zonetxt == NULL)
7097 		return (ISC_R_SUCCESS);
7098 	if (zonename != NULL)
7099 		*zonename = zonetxt;
7100 
7101 	/* Look for the optional class name. */
7102 	classtxt = next_token(&input, " \t");
7103 	if (classtxt != NULL) {
7104 		/* Look for the optional view name. */
7105 		viewtxt = next_token(&input, " \t");
7106 	}
7107 
7108 	dns_fixedname_init(&fname);
7109 	name = dns_fixedname_name(&fname);
7110 	CHECK(dns_name_fromstring(name, zonetxt, 0, NULL));
7111 
7112 	if (classtxt != NULL) {
7113 		isc_textregion_t r;
7114 		r.base = classtxt;
7115 		r.length = strlen(classtxt);
7116 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
7117 	} else
7118 		rdclass = dns_rdataclass_in;
7119 
7120 	if (viewtxt == NULL) {
7121 		result = dns_viewlist_findzone(&server->viewlist, name,
7122 					       ISC_TF(classtxt == NULL),
7123 					       rdclass, zonep);
7124 		if (result == ISC_R_NOTFOUND)
7125 			snprintf(problem, sizeof(problem),
7126 				 "no matching zone '%s' in any view",
7127 				 zonetxt);
7128 		else if (result == ISC_R_MULTIPLE)
7129 			snprintf(problem, sizeof(problem),
7130 				 "zone '%s' was found in multiple views",
7131 				 zonetxt);
7132 	} else {
7133 		result = dns_viewlist_find(&server->viewlist, viewtxt,
7134 					   rdclass, &view);
7135 		if (result != ISC_R_SUCCESS) {
7136 			snprintf(problem, sizeof(problem),
7137 				 "no matching view '%s'", viewtxt);
7138 			goto report;
7139 		}
7140 
7141 		result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
7142 		if (result != ISC_R_SUCCESS)
7143 			snprintf(problem, sizeof(problem),
7144 				 "no matching zone '%s' in view '%s'",
7145 				 zonetxt, viewtxt);
7146 	}
7147 
7148 	/* Partial match? */
7149 	if (result != ISC_R_SUCCESS && *zonep != NULL)
7150 		dns_zone_detach(zonep);
7151 	if (result == DNS_R_PARTIALMATCH)
7152 		result = ISC_R_NOTFOUND;
7153  report:
7154 	if (result != ISC_R_SUCCESS) {
7155 		isc_result_t tresult;
7156 
7157 		tresult = putstr(text, problem);
7158 		if (tresult == ISC_R_SUCCESS)
7159 			(void) putnull(text);
7160 	}
7161 
7162  cleanup:
7163 	if (view != NULL)
7164 		dns_view_detach(&view);
7165 
7166 	return (result);
7167 }
7168 
7169 /*
7170  * Act on a "retransfer" command from the command channel.
7171  */
7172 isc_result_t
7173 ns_server_retransfercommand(ns_server_t *server, char *args,
7174 			    isc_buffer_t *text)
7175 {
7176 	isc_result_t result;
7177 	dns_zone_t *zone = NULL;
7178 	dns_zone_t *raw = NULL;
7179 	dns_zonetype_t type;
7180 
7181 	result = zone_from_args(server, args, NULL, &zone, NULL,
7182 				text, ISC_TRUE);
7183 	if (result != ISC_R_SUCCESS)
7184 		return (result);
7185 	if (zone == NULL)
7186 		return (ISC_R_UNEXPECTEDEND);
7187 	dns_zone_getraw(zone, &raw);
7188 	if (raw != NULL) {
7189 		dns_zone_detach(&zone);
7190 		dns_zone_attach(raw, &zone);
7191 		dns_zone_detach(&raw);
7192 	}
7193 	type = dns_zone_gettype(zone);
7194 	if (type == dns_zone_slave || type == dns_zone_stub)
7195 		dns_zone_forcereload(zone);
7196 	else
7197 		result = ISC_R_NOTFOUND;
7198 	dns_zone_detach(&zone);
7199 	return (result);
7200 }
7201 
7202 /*
7203  * Act on a "reload" command from the command channel.
7204  */
7205 isc_result_t
7206 ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
7207 	isc_result_t result;
7208 	dns_zone_t *zone = NULL;
7209 	dns_zonetype_t type;
7210 	const char *msg = NULL;
7211 
7212 	result = zone_from_args(server, args, NULL, &zone, NULL,
7213 				text, ISC_TRUE);
7214 	if (result != ISC_R_SUCCESS)
7215 		return (result);
7216 	if (zone == NULL) {
7217 		result = reload(server);
7218 		if (result == ISC_R_SUCCESS)
7219 			msg = "server reload successful";
7220 	} else {
7221 		type = dns_zone_gettype(zone);
7222 		if (type == dns_zone_slave || type == dns_zone_stub) {
7223 			dns_zone_refresh(zone);
7224 			dns_zone_detach(&zone);
7225 			msg = "zone refresh queued";
7226 		} else {
7227 			result = dns_zone_load(zone);
7228 			dns_zone_detach(&zone);
7229 			switch (result) {
7230 			case ISC_R_SUCCESS:
7231 				 msg = "zone reload successful";
7232 				 break;
7233 			case DNS_R_CONTINUE:
7234 				msg = "zone reload queued";
7235 				result = ISC_R_SUCCESS;
7236 				break;
7237 			case DNS_R_UPTODATE:
7238 				msg = "zone reload up-to-date";
7239 				result = ISC_R_SUCCESS;
7240 				break;
7241 			default:
7242 				/* failure message will be generated by rndc */
7243 				break;
7244 			}
7245 		}
7246 	}
7247 	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
7248 		isc_buffer_putmem(text, (const unsigned char *)msg,
7249 				  strlen(msg) + 1);
7250 	return (result);
7251 }
7252 
7253 /*
7254  * Act on a "reconfig" command from the command channel.
7255  */
7256 isc_result_t
7257 ns_server_reconfigcommand(ns_server_t *server, char *args) {
7258 	UNUSED(args);
7259 
7260 	reconfig(server);
7261 	return (ISC_R_SUCCESS);
7262 }
7263 
7264 /*
7265  * Act on a "notify" command from the command channel.
7266  */
7267 isc_result_t
7268 ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
7269 	isc_result_t result;
7270 	dns_zone_t *zone = NULL;
7271 	const unsigned char msg[] = "zone notify queued";
7272 
7273 	result = zone_from_args(server, args, NULL, &zone, NULL,
7274 				text, ISC_TRUE);
7275 	if (result != ISC_R_SUCCESS)
7276 		return (result);
7277 	if (zone == NULL)
7278 		return (ISC_R_UNEXPECTEDEND);
7279 
7280 	dns_zone_notify(zone);
7281 	dns_zone_detach(&zone);
7282 	if (sizeof(msg) <= isc_buffer_availablelength(text))
7283 		isc_buffer_putmem(text, msg, sizeof(msg));
7284 
7285 	return (ISC_R_SUCCESS);
7286 }
7287 
7288 /*
7289  * Act on a "refresh" command from the command channel.
7290  */
7291 isc_result_t
7292 ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
7293 	isc_result_t result;
7294 	dns_zone_t *zone = NULL, *raw = NULL;
7295 	const unsigned char msg1[] = "zone refresh queued";
7296 	const unsigned char msg2[] = "not a slave or stub zone";
7297 	dns_zonetype_t type;
7298 
7299 	result = zone_from_args(server, args, NULL, &zone, NULL,
7300 				text, ISC_TRUE);
7301 	if (result != ISC_R_SUCCESS)
7302 		return (result);
7303 	if (zone == NULL)
7304 		return (ISC_R_UNEXPECTEDEND);
7305 
7306 	dns_zone_getraw(zone, &raw);
7307 	if (raw != NULL) {
7308 		dns_zone_detach(&zone);
7309 		dns_zone_attach(raw, &zone);
7310 		dns_zone_detach(&raw);
7311 	}
7312 
7313 	type = dns_zone_gettype(zone);
7314 	if (type == dns_zone_slave || type == dns_zone_stub) {
7315 		dns_zone_refresh(zone);
7316 		dns_zone_detach(&zone);
7317 		if (sizeof(msg1) <= isc_buffer_availablelength(text))
7318 			isc_buffer_putmem(text, msg1, sizeof(msg1));
7319 		return (ISC_R_SUCCESS);
7320 	}
7321 
7322 	dns_zone_detach(&zone);
7323 	if (sizeof(msg2) <= isc_buffer_availablelength(text))
7324 		isc_buffer_putmem(text, msg2, sizeof(msg2));
7325 	return (ISC_R_FAILURE);
7326 }
7327 
7328 isc_result_t
7329 ns_server_togglequerylog(ns_server_t *server, char *args) {
7330 	isc_boolean_t value;
7331 	char *ptr;
7332 
7333 	/* Skip the command name. */
7334 	ptr = next_token(&args, " \t");
7335 	if (ptr == NULL)
7336 		return (ISC_R_UNEXPECTEDEND);
7337 
7338 	ptr = next_token(&args, " \t");
7339 	if (ptr == NULL)
7340 		value = server->log_queries ? ISC_FALSE : ISC_TRUE;
7341 	else if (strcasecmp(ptr, "yes") == 0 || strcasecmp(ptr, "on") == 0)
7342 		value = ISC_TRUE;
7343 	else if (strcasecmp(ptr, "no") == 0 || strcasecmp(ptr, "off") == 0)
7344 		value = ISC_FALSE;
7345 	else
7346 		return (ISC_R_NOTFOUND);
7347 
7348 	if (server->log_queries == value)
7349 		return (ISC_R_SUCCESS);
7350 
7351 	server->log_queries = value;
7352 
7353 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7354 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7355 		      "query logging is now %s",
7356 		      server->log_queries ? "on" : "off");
7357 	return (ISC_R_SUCCESS);
7358 }
7359 
7360 static isc_result_t
7361 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
7362 			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
7363 			 isc_uint16_t family, ns_listenlist_t **target)
7364 {
7365 	isc_result_t result;
7366 	const cfg_listelt_t *element;
7367 	ns_listenlist_t *dlist = NULL;
7368 
7369 	REQUIRE(target != NULL && *target == NULL);
7370 
7371 	result = ns_listenlist_create(mctx, &dlist);
7372 	if (result != ISC_R_SUCCESS)
7373 		return (result);
7374 
7375 	for (element = cfg_list_first(listenlist);
7376 	     element != NULL;
7377 	     element = cfg_list_next(element))
7378 	{
7379 		ns_listenelt_t *delt = NULL;
7380 		const cfg_obj_t *listener = cfg_listelt_value(element);
7381 		result = ns_listenelt_fromconfig(listener, config, actx,
7382 						 mctx, family, &delt);
7383 		if (result != ISC_R_SUCCESS)
7384 			goto cleanup;
7385 		ISC_LIST_APPEND(dlist->elts, delt, link);
7386 	}
7387 	*target = dlist;
7388 	return (ISC_R_SUCCESS);
7389 
7390  cleanup:
7391 	ns_listenlist_detach(&dlist);
7392 	return (result);
7393 }
7394 
7395 /*
7396  * Create a listen list from the corresponding configuration
7397  * data structure.
7398  */
7399 static isc_result_t
7400 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
7401 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
7402 			isc_uint16_t family, ns_listenelt_t **target)
7403 {
7404 	isc_result_t result;
7405 	const cfg_obj_t *portobj, *dscpobj;
7406 	in_port_t port;
7407 	isc_dscp_t dscp = -1;
7408 	ns_listenelt_t *delt = NULL;
7409 	REQUIRE(target != NULL && *target == NULL);
7410 
7411 	portobj = cfg_tuple_get(listener, "port");
7412 	if (!cfg_obj_isuint32(portobj)) {
7413 		if (ns_g_port != 0) {
7414 			port = ns_g_port;
7415 		} else {
7416 			result = ns_config_getport(config, &port);
7417 			if (result != ISC_R_SUCCESS)
7418 				return (result);
7419 		}
7420 	} else {
7421 		if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
7422 			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
7423 				    "port value '%u' is out of range",
7424 				    cfg_obj_asuint32(portobj));
7425 			return (ISC_R_RANGE);
7426 		}
7427 		port = (in_port_t)cfg_obj_asuint32(portobj);
7428 	}
7429 
7430 	dscpobj = cfg_tuple_get(listener, "dscp");
7431 	if (!cfg_obj_isuint32(dscpobj))
7432 		dscp = ns_g_dscp;
7433 	else {
7434 		if (cfg_obj_asuint32(dscpobj) > 63) {
7435 			cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
7436 				    "dscp value '%u' is out of range",
7437 				    cfg_obj_asuint32(dscpobj));
7438 			return (ISC_R_RANGE);
7439 		}
7440 		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
7441 	}
7442 
7443 	result = ns_listenelt_create(mctx, port, dscp, NULL, &delt);
7444 	if (result != ISC_R_SUCCESS)
7445 		return (result);
7446 
7447 	result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"),
7448 				     config, ns_g_lctx, actx, mctx, 0,
7449 				     family, &delt->acl);
7450 	if (result != ISC_R_SUCCESS) {
7451 		ns_listenelt_destroy(delt);
7452 		return (result);
7453 	}
7454 	*target = delt;
7455 	return (ISC_R_SUCCESS);
7456 }
7457 
7458 isc_result_t
7459 ns_server_dumpstats(ns_server_t *server) {
7460 	isc_result_t result;
7461 	FILE *fp = NULL;
7462 
7463 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
7464 		"could not open statistics dump file", server->statsfile);
7465 
7466 	result = ns_stats_dump(server, fp);
7467 
7468  cleanup:
7469 	if (fp != NULL)
7470 		(void)isc_stdio_close(fp);
7471 	if (result == ISC_R_SUCCESS)
7472 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7473 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7474 			      "dumpstats complete");
7475 	else
7476 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7477 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7478 			      "dumpstats failed: %s",
7479 			      dns_result_totext(result));
7480 	return (result);
7481 }
7482 
7483 static isc_result_t
7484 add_zone_tolist(dns_zone_t *zone, void *uap) {
7485 	struct dumpcontext *dctx = uap;
7486 	struct zonelistentry *zle;
7487 
7488 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
7489 	if (zle ==  NULL)
7490 		return (ISC_R_NOMEMORY);
7491 	zle->zone = NULL;
7492 	dns_zone_attach(zone, &zle->zone);
7493 	ISC_LINK_INIT(zle, link);
7494 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
7495 	return (ISC_R_SUCCESS);
7496 }
7497 
7498 static isc_result_t
7499 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
7500 	struct viewlistentry *vle;
7501 	isc_result_t result = ISC_R_SUCCESS;
7502 
7503 	/*
7504 	 * Prevent duplicate views.
7505 	 */
7506 	for (vle = ISC_LIST_HEAD(dctx->viewlist);
7507 	     vle != NULL;
7508 	     vle = ISC_LIST_NEXT(vle, link))
7509 		if (vle->view == view)
7510 			return (ISC_R_SUCCESS);
7511 
7512 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
7513 	if (vle == NULL)
7514 		return (ISC_R_NOMEMORY);
7515 	vle->view = NULL;
7516 	dns_view_attach(view, &vle->view);
7517 	ISC_LINK_INIT(vle, link);
7518 	ISC_LIST_INIT(vle->zonelist);
7519 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
7520 	if (dctx->dumpzones)
7521 		result = dns_zt_apply(view->zonetable, ISC_TRUE,
7522 				      add_zone_tolist, dctx);
7523 	return (result);
7524 }
7525 
7526 static void
7527 dumpcontext_destroy(struct dumpcontext *dctx) {
7528 	struct viewlistentry *vle;
7529 	struct zonelistentry *zle;
7530 
7531 	vle = ISC_LIST_HEAD(dctx->viewlist);
7532 	while (vle != NULL) {
7533 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
7534 		zle = ISC_LIST_HEAD(vle->zonelist);
7535 		while (zle != NULL) {
7536 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
7537 			dns_zone_detach(&zle->zone);
7538 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
7539 			zle = ISC_LIST_HEAD(vle->zonelist);
7540 		}
7541 		dns_view_detach(&vle->view);
7542 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
7543 		vle = ISC_LIST_HEAD(dctx->viewlist);
7544 	}
7545 	if (dctx->version != NULL)
7546 		dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
7547 	if (dctx->db != NULL)
7548 		dns_db_detach(&dctx->db);
7549 	if (dctx->cache != NULL)
7550 		dns_db_detach(&dctx->cache);
7551 	if (dctx->task != NULL)
7552 		isc_task_detach(&dctx->task);
7553 	if (dctx->fp != NULL)
7554 		(void)isc_stdio_close(dctx->fp);
7555 	if (dctx->mdctx != NULL)
7556 		dns_dumpctx_detach(&dctx->mdctx);
7557 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
7558 }
7559 
7560 static void
7561 dumpdone(void *arg, isc_result_t result) {
7562 	struct dumpcontext *dctx = arg;
7563 	char buf[1024+32];
7564 	const dns_master_style_t *style;
7565 
7566 	if (result != ISC_R_SUCCESS)
7567 		goto cleanup;
7568 	if (dctx->mdctx != NULL)
7569 		dns_dumpctx_detach(&dctx->mdctx);
7570 	if (dctx->view == NULL) {
7571 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
7572 		if (dctx->view == NULL)
7573 			goto done;
7574 		INSIST(dctx->zone == NULL);
7575 	} else
7576 		goto resume;
7577  nextview:
7578 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
7579  resume:
7580 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
7581 		fprintf(dctx->fp,
7582 			";\n; Cache of view '%s' is shared as '%s'\n",
7583 			dctx->view->view->name,
7584 			dns_cache_getname(dctx->view->view->cache));
7585 	} else if (dctx->zone == NULL && dctx->cache == NULL &&
7586 		   dctx->dumpcache)
7587 	{
7588 		style = &dns_master_style_cache;
7589 		/* start cache dump */
7590 		if (dctx->view->view->cachedb != NULL)
7591 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
7592 		if (dctx->cache != NULL) {
7593 			fprintf(dctx->fp,
7594 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
7595 				dctx->view->view->name,
7596 				dns_cache_getname(dctx->view->view->cache));
7597 			result = dns_master_dumptostreaminc(dctx->mctx,
7598 							    dctx->cache, NULL,
7599 							    style, dctx->fp,
7600 							    dctx->task,
7601 							    dumpdone, dctx,
7602 							    &dctx->mdctx);
7603 			if (result == DNS_R_CONTINUE)
7604 				return;
7605 			if (result == ISC_R_NOTIMPLEMENTED)
7606 				fprintf(dctx->fp, "; %s\n",
7607 					dns_result_totext(result));
7608 			else if (result != ISC_R_SUCCESS)
7609 				goto cleanup;
7610 		}
7611 	}
7612 	if (dctx->cache != NULL) {
7613 		dns_adb_dump(dctx->view->view->adb, dctx->fp);
7614 		dns_resolver_printbadcache(dctx->view->view->resolver,
7615 					   dctx->fp);
7616 		dns_db_detach(&dctx->cache);
7617 	}
7618 	if (dctx->dumpzones) {
7619 		style = &dns_master_style_full;
7620  nextzone:
7621 		if (dctx->version != NULL)
7622 			dns_db_closeversion(dctx->db, &dctx->version,
7623 					    ISC_FALSE);
7624 		if (dctx->db != NULL)
7625 			dns_db_detach(&dctx->db);
7626 		if (dctx->zone == NULL)
7627 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
7628 		else
7629 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
7630 		if (dctx->zone != NULL) {
7631 			/* start zone dump */
7632 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
7633 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
7634 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
7635 			if (result != ISC_R_SUCCESS) {
7636 				fprintf(dctx->fp, "; %s\n",
7637 					dns_result_totext(result));
7638 				goto nextzone;
7639 			}
7640 			dns_db_currentversion(dctx->db, &dctx->version);
7641 			result = dns_master_dumptostreaminc(dctx->mctx,
7642 							    dctx->db,
7643 							    dctx->version,
7644 							    style, dctx->fp,
7645 							    dctx->task,
7646 							    dumpdone, dctx,
7647 							    &dctx->mdctx);
7648 			if (result == DNS_R_CONTINUE)
7649 				return;
7650 			if (result == ISC_R_NOTIMPLEMENTED) {
7651 				fprintf(dctx->fp, "; %s\n",
7652 					dns_result_totext(result));
7653 				result = ISC_R_SUCCESS;
7654 				POST(result);
7655 				goto nextzone;
7656 			}
7657 			if (result != ISC_R_SUCCESS)
7658 				goto cleanup;
7659 		}
7660 	}
7661 	if (dctx->view != NULL)
7662 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
7663 	if (dctx->view != NULL)
7664 		goto nextview;
7665  done:
7666 	fprintf(dctx->fp, "; Dump complete\n");
7667 	result = isc_stdio_flush(dctx->fp);
7668 	if (result == ISC_R_SUCCESS)
7669 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7670 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7671 			      "dumpdb complete");
7672  cleanup:
7673 	if (result != ISC_R_SUCCESS)
7674 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7675 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7676 			      "dumpdb failed: %s", dns_result_totext(result));
7677 	dumpcontext_destroy(dctx);
7678 }
7679 
7680 isc_result_t
7681 ns_server_dumpdb(ns_server_t *server, char *args) {
7682 	struct dumpcontext *dctx = NULL;
7683 	dns_view_t *view;
7684 	isc_result_t result;
7685 	char *ptr;
7686 	const char *sep;
7687 
7688 	/* Skip the command name. */
7689 	ptr = next_token(&args, " \t");
7690 	if (ptr == NULL)
7691 		return (ISC_R_UNEXPECTEDEND);
7692 
7693 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
7694 	if (dctx == NULL)
7695 		return (ISC_R_NOMEMORY);
7696 
7697 	dctx->mctx = server->mctx;
7698 	dctx->dumpcache = ISC_TRUE;
7699 	dctx->dumpzones = ISC_FALSE;
7700 	dctx->fp = NULL;
7701 	ISC_LIST_INIT(dctx->viewlist);
7702 	dctx->view = NULL;
7703 	dctx->zone = NULL;
7704 	dctx->cache = NULL;
7705 	dctx->mdctx = NULL;
7706 	dctx->db = NULL;
7707 	dctx->cache = NULL;
7708 	dctx->task = NULL;
7709 	dctx->version = NULL;
7710 	isc_task_attach(server->task, &dctx->task);
7711 
7712 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
7713 		"could not open dump file", server->dumpfile);
7714 
7715 	sep = (args == NULL) ? "" : ": ";
7716 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7717 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7718 		      "dumpdb started%s%s", sep, (args != NULL) ? args : "");
7719 
7720 	ptr = next_token(&args, " \t");
7721 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
7722 		dctx->dumpzones = ISC_TRUE;
7723 		dctx->dumpcache = ISC_TRUE;
7724 		ptr = next_token(&args, " \t");
7725 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
7726 		dctx->dumpzones = ISC_FALSE;
7727 		dctx->dumpcache = ISC_TRUE;
7728 		ptr = next_token(&args, " \t");
7729 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
7730 		dctx->dumpzones = ISC_TRUE;
7731 		dctx->dumpcache = ISC_FALSE;
7732 		ptr = next_token(&args, " \t");
7733 	}
7734 
7735  nextview:
7736 	for (view = ISC_LIST_HEAD(server->viewlist);
7737 	     view != NULL;
7738 	     view = ISC_LIST_NEXT(view, link))
7739 	{
7740 		if (ptr != NULL && strcmp(view->name, ptr) != 0)
7741 			continue;
7742 		CHECK(add_view_tolist(dctx, view));
7743 	}
7744 	if (ptr != NULL) {
7745 		ptr = next_token(&args, " \t");
7746 		if (ptr != NULL)
7747 			goto nextview;
7748 	}
7749 	dumpdone(dctx, ISC_R_SUCCESS);
7750 	return (ISC_R_SUCCESS);
7751 
7752  cleanup:
7753 	if (dctx != NULL)
7754 		dumpcontext_destroy(dctx);
7755 	return (result);
7756 }
7757 
7758 isc_result_t
7759 ns_server_dumpsecroots(ns_server_t *server, char *args) {
7760 	dns_view_t *view;
7761 	dns_keytable_t *secroots = NULL;
7762 	isc_result_t result;
7763 	char *ptr;
7764 	FILE *fp = NULL;
7765 	isc_time_t now;
7766 	char tbuf[64];
7767 
7768 	/* Skip the command name. */
7769 	ptr = next_token(&args, " \t");
7770 	if (ptr == NULL)
7771 		return (ISC_R_UNEXPECTEDEND);
7772 
7773 	ptr = next_token(&args, " \t");
7774 
7775 	CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp),
7776 		"could not open secroots dump file", server->secrootsfile);
7777 	TIME_NOW(&now);
7778 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
7779 	fprintf(fp, "%s\n", tbuf);
7780 
7781 	do {
7782 		for (view = ISC_LIST_HEAD(server->viewlist);
7783 		     view != NULL;
7784 		     view = ISC_LIST_NEXT(view, link))
7785 		{
7786 			if (ptr != NULL && strcmp(view->name, ptr) != 0)
7787 				continue;
7788 			if (secroots != NULL)
7789 				dns_keytable_detach(&secroots);
7790 			result = dns_view_getsecroots(view, &secroots);
7791 			if (result == ISC_R_NOTFOUND) {
7792 				result = ISC_R_SUCCESS;
7793 				continue;
7794 			}
7795 			fprintf(fp, "\n Start view %s\n\n", view->name);
7796 			result = dns_keytable_dump(secroots, fp);
7797 			if (result != ISC_R_SUCCESS)
7798 				fprintf(fp, " dumpsecroots failed: %s\n",
7799 					isc_result_totext(result));
7800 		}
7801 		if (ptr != NULL)
7802 			ptr = next_token(&args, " \t");
7803 	} while (ptr != NULL);
7804 
7805  cleanup:
7806 	if (secroots != NULL)
7807 		dns_keytable_detach(&secroots);
7808 	if (fp != NULL)
7809 		(void)isc_stdio_close(fp);
7810 	if (result == ISC_R_SUCCESS)
7811 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7812 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7813 			      "dumpsecroots complete");
7814 	else
7815 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7816 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7817 			      "dumpsecroots failed: %s",
7818 			      dns_result_totext(result));
7819 	return (result);
7820 }
7821 
7822 isc_result_t
7823 ns_server_dumprecursing(ns_server_t *server) {
7824 	FILE *fp = NULL;
7825 	isc_result_t result;
7826 
7827 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
7828 		"could not open dump file", server->recfile);
7829 	fprintf(fp,";\n; Recursing Queries\n;\n");
7830 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
7831 	fprintf(fp, "; Dump complete\n");
7832 
7833  cleanup:
7834 	if (fp != NULL)
7835 		result = isc_stdio_close(fp);
7836 	if (result == ISC_R_SUCCESS)
7837 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7838 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7839 			      "dumprecursing complete");
7840 	else
7841 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7842 			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7843 			      "dumprecursing failed: %s",
7844 			      dns_result_totext(result));
7845 	return (result);
7846 }
7847 
7848 isc_result_t
7849 ns_server_setdebuglevel(ns_server_t *server, char *args) {
7850 	char *ptr;
7851 	char *levelstr;
7852 	char *endp;
7853 	long newlevel;
7854 
7855 	UNUSED(server);
7856 
7857 	/* Skip the command name. */
7858 	ptr = next_token(&args, " \t");
7859 	if (ptr == NULL)
7860 		return (ISC_R_UNEXPECTEDEND);
7861 
7862 	/* Look for the new level name. */
7863 	levelstr = next_token(&args, " \t");
7864 	if (levelstr == NULL) {
7865 		if (ns_g_debuglevel < 99)
7866 			ns_g_debuglevel++;
7867 	} else {
7868 		newlevel = strtol(levelstr, &endp, 10);
7869 		if (*endp != '\0' || newlevel < 0 || newlevel > 99)
7870 			return (ISC_R_RANGE);
7871 		ns_g_debuglevel = (unsigned int)newlevel;
7872 	}
7873 	isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
7874 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7875 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7876 		      "debug level is now %d", ns_g_debuglevel);
7877 	return (ISC_R_SUCCESS);
7878 }
7879 
7880 isc_result_t
7881 ns_server_validation(ns_server_t *server, char *args, isc_buffer_t *text) {
7882 	char *ptr, *viewname;
7883 	dns_view_t *view;
7884 	isc_boolean_t changed = ISC_FALSE;
7885 	isc_result_t result;
7886 	isc_boolean_t enable = ISC_TRUE, set = ISC_TRUE, first = ISC_TRUE;
7887 
7888 	/* Skip the command name. */
7889 	ptr = next_token(&args, " \t");
7890 	if (ptr == NULL)
7891 		return (ISC_R_UNEXPECTEDEND);
7892 
7893 	/* Find out what we are to do. */
7894 	ptr = next_token(&args, " \t");
7895 	if (ptr == NULL)
7896 		return (ISC_R_UNEXPECTEDEND);
7897 
7898 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
7899 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
7900 		enable = ISC_TRUE;
7901 	else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
7902 		 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
7903 		enable = ISC_FALSE;
7904 	else if (!strcasecmp(ptr, "check"))
7905 		set = ISC_FALSE;
7906 	else
7907 		return (DNS_R_SYNTAX);
7908 
7909 	/* Look for the view name. */
7910 	viewname = next_token(&args, " \t");
7911 
7912 	result = isc_task_beginexclusive(server->task);
7913 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7914 	for (view = ISC_LIST_HEAD(server->viewlist);
7915 	     view != NULL;
7916 	     view = ISC_LIST_NEXT(view, link))
7917 	{
7918 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
7919 			continue;
7920 		result = dns_view_flushcache(view);
7921 		if (result != ISC_R_SUCCESS)
7922 			goto cleanup;
7923 
7924 		if (set) {
7925 			view->enablevalidation = enable;
7926 			changed = ISC_TRUE;
7927 		} else {
7928 			if (!first)
7929 				CHECK(putstr(text, "\n"));
7930 			CHECK(putstr(text, "DNSSEC validation is "));
7931 			CHECK(putstr(text, view->enablevalidation
7932 				       ? "enabled" : "disabled"));
7933 			CHECK(putstr(text, " (view "));
7934 			CHECK(putstr(text, view->name));
7935 			CHECK(putstr(text, ")"));
7936 			CHECK(putnull(text));
7937 			first = ISC_FALSE;
7938 		}
7939 	}
7940 
7941 	if (!set)
7942 		result = ISC_R_SUCCESS;
7943 	else if (changed)
7944 		result = ISC_R_SUCCESS;
7945 	else
7946 		result = ISC_R_FAILURE;
7947  cleanup:
7948 	isc_task_endexclusive(server->task);
7949 	return (result);
7950 }
7951 
7952 isc_result_t
7953 ns_server_flushcache(ns_server_t *server, char *args) {
7954 	char *ptr, *viewname;
7955 	dns_view_t *view;
7956 	isc_boolean_t flushed;
7957 	isc_boolean_t found;
7958 	isc_result_t result;
7959 	ns_cache_t *nsc;
7960 
7961 	/* Skip the command name. */
7962 	ptr = next_token(&args, " \t");
7963 	if (ptr == NULL)
7964 		return (ISC_R_UNEXPECTEDEND);
7965 
7966 	/* Look for the view name. */
7967 	viewname = next_token(&args, " \t");
7968 
7969 	result = isc_task_beginexclusive(server->task);
7970 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7971 	flushed = ISC_TRUE;
7972 	found = ISC_FALSE;
7973 
7974 	/*
7975 	 * Flushing a cache is tricky when caches are shared by multiple views.
7976 	 * We first identify which caches should be flushed in the local cache
7977 	 * list, flush these caches, and then update other views that refer to
7978 	 * the flushed cache DB.
7979 	 */
7980 	if (viewname != NULL) {
7981 		/*
7982 		 * Mark caches that need to be flushed.  This is an O(#view^2)
7983 		 * operation in the very worst case, but should be normally
7984 		 * much more lightweight because only a few (most typically just
7985 		 * one) views will match.
7986 		 */
7987 		for (view = ISC_LIST_HEAD(server->viewlist);
7988 		     view != NULL;
7989 		     view = ISC_LIST_NEXT(view, link))
7990 		{
7991 			if (strcasecmp(viewname, view->name) != 0)
7992 				continue;
7993 			found = ISC_TRUE;
7994 			for (nsc = ISC_LIST_HEAD(server->cachelist);
7995 			     nsc != NULL;
7996 			     nsc = ISC_LIST_NEXT(nsc, link)) {
7997 				if (nsc->cache == view->cache)
7998 					break;
7999 			}
8000 			INSIST(nsc != NULL);
8001 			nsc->needflush = ISC_TRUE;
8002 		}
8003 	} else
8004 		found = ISC_TRUE;
8005 
8006 	/* Perform flush */
8007 	for (nsc = ISC_LIST_HEAD(server->cachelist);
8008 	     nsc != NULL;
8009 	     nsc = ISC_LIST_NEXT(nsc, link)) {
8010 		if (viewname != NULL && !nsc->needflush)
8011 			continue;
8012 		nsc->needflush = ISC_TRUE;
8013 		result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
8014 		if (result != ISC_R_SUCCESS) {
8015 			flushed = ISC_FALSE;
8016 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8017 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
8018 				      "flushing cache in view '%s' failed: %s",
8019 				      nsc->primaryview->name,
8020 				      isc_result_totext(result));
8021 		}
8022 	}
8023 
8024 	/*
8025 	 * Fix up views that share a flushed cache: let the views update the
8026 	 * cache DB they're referring to.  This could also be an expensive
8027 	 * operation, but should typically be marginal: the inner loop is only
8028 	 * necessary for views that share a cache, and if there are many such
8029 	 * views the number of shared cache should normally be small.
8030 	 * A worst case is that we have n views and n/2 caches, each shared by
8031 	 * two views.  Then this will be a O(n^2/4) operation.
8032 	 */
8033 	for (view = ISC_LIST_HEAD(server->viewlist);
8034 	     view != NULL;
8035 	     view = ISC_LIST_NEXT(view, link))
8036 	{
8037 		if (!dns_view_iscacheshared(view))
8038 			continue;
8039 		for (nsc = ISC_LIST_HEAD(server->cachelist);
8040 		     nsc != NULL;
8041 		     nsc = ISC_LIST_NEXT(nsc, link)) {
8042 			if (!nsc->needflush || nsc->cache != view->cache)
8043 				continue;
8044 			result = dns_view_flushcache2(view, ISC_TRUE);
8045 			if (result != ISC_R_SUCCESS) {
8046 				flushed = ISC_FALSE;
8047 				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8048 					      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
8049 					      "fixing cache in view '%s' "
8050 					      "failed: %s", view->name,
8051 					      isc_result_totext(result));
8052 			}
8053 		}
8054 	}
8055 
8056 	/* Cleanup the cache list. */
8057 	for (nsc = ISC_LIST_HEAD(server->cachelist);
8058 	     nsc != NULL;
8059 	     nsc = ISC_LIST_NEXT(nsc, link)) {
8060 		nsc->needflush = ISC_FALSE;
8061 	}
8062 
8063 	if (flushed && found) {
8064 		if (viewname != NULL)
8065 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8066 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8067 				      "flushing cache in view '%s' succeeded",
8068 				      viewname);
8069 		else
8070 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8071 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8072 				      "flushing caches in all views succeeded");
8073 		result = ISC_R_SUCCESS;
8074 	} else {
8075 		if (!found) {
8076 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8077 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
8078 				      "flushing cache in view '%s' failed: "
8079 				      "view not found", viewname);
8080 			result = ISC_R_NOTFOUND;
8081 		} else
8082 			result = ISC_R_FAILURE;
8083 	}
8084 	isc_task_endexclusive(server->task);
8085 	return (result);
8086 }
8087 
8088 isc_result_t
8089 ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) {
8090 	char *target, *viewname;
8091 	dns_view_t *view;
8092 	isc_boolean_t flushed;
8093 	isc_boolean_t found;
8094 	isc_result_t result;
8095 	isc_buffer_t b;
8096 	dns_fixedname_t fixed;
8097 	dns_name_t *name;
8098 
8099 	/* Skip the command name. */
8100 	target = next_token(&args, " \t");
8101 	if (target == NULL)
8102 		return (ISC_R_UNEXPECTEDEND);
8103 
8104 	/* Find the domain name to flush. */
8105 	target = next_token(&args, " \t");
8106 	if (target == NULL)
8107 		return (ISC_R_UNEXPECTEDEND);
8108 
8109 	isc_buffer_constinit(&b, target, strlen(target));
8110 	isc_buffer_add(&b, strlen(target));
8111 	dns_fixedname_init(&fixed);
8112 	name = dns_fixedname_name(&fixed);
8113 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
8114 	if (result != ISC_R_SUCCESS)
8115 		return (result);
8116 
8117 	/* Look for the view name. */
8118 	viewname = next_token(&args, " \t");
8119 
8120 	result = isc_task_beginexclusive(server->task);
8121 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8122 	flushed = ISC_TRUE;
8123 	found = ISC_FALSE;
8124 	for (view = ISC_LIST_HEAD(server->viewlist);
8125 	     view != NULL;
8126 	     view = ISC_LIST_NEXT(view, link))
8127 	{
8128 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
8129 			continue;
8130 		found = ISC_TRUE;
8131 		/*
8132 		 * It's a little inefficient to try flushing name for all views
8133 		 * if some of the views share a single cache.  But since the
8134 		 * operation is lightweight we prefer simplicity here.
8135 		 */
8136 		result = dns_view_flushnode(view, name, tree);
8137 		if (result != ISC_R_SUCCESS) {
8138 			flushed = ISC_FALSE;
8139 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8140 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
8141 				      "flushing %s '%s' in cache view '%s' "
8142 				      "failed: %s",
8143 				      tree ? "tree" : "name",
8144 				      target, view->name,
8145 				      isc_result_totext(result));
8146 		}
8147 	}
8148 	if (flushed && found) {
8149 		if (viewname != NULL)
8150 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8151 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8152 				      "flushing %s '%s' in cache view '%s' "
8153 				      "succeeded",
8154 				      tree ? "tree" : "name",
8155 				      target, viewname);
8156 		else
8157 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8158 				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8159 				      "flushing %s '%s' in all cache views "
8160 				      "succeeded",
8161 				      tree ? "tree" : "name",
8162 				      target);
8163 		result = ISC_R_SUCCESS;
8164 	} else {
8165 		if (!found)
8166 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8167 				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
8168 				      "flushing %s '%s' in cache view '%s' "
8169 				      "failed: view not found",
8170 				      tree ? "tree" : "name",
8171 				      target, viewname);
8172 		result = ISC_R_FAILURE;
8173 	}
8174 	isc_task_endexclusive(server->task);
8175 	return (result);
8176 }
8177 
8178 isc_result_t
8179 ns_server_status(ns_server_t *server, isc_buffer_t *text) {
8180 	int zonecount, xferrunning, xferdeferred, soaqueries;
8181 	unsigned int n;
8182 	const char *ob = "", *cb = "", *alt = "";
8183 	char boottime[80], configtime[80];
8184 
8185 	if (ns_g_server->version_set) {
8186 		ob = " (";
8187 		cb = ")";
8188 		if (ns_g_server->version == NULL)
8189 			alt = "version.bind/txt/ch disabled";
8190 		else
8191 			alt = ns_g_server->version;
8192 	}
8193 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
8194 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
8195 					   DNS_ZONESTATE_XFERRUNNING);
8196 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
8197 					    DNS_ZONESTATE_XFERDEFERRED);
8198 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
8199 					  DNS_ZONESTATE_SOAQUERY);
8200 
8201 	isc_time_formathttptimestamp(&ns_g_boottime, boottime,
8202 				     sizeof(boottime));
8203 	isc_time_formathttptimestamp(&ns_g_configtime, configtime,
8204 				     sizeof(configtime));
8205 
8206 	n = snprintf((char *)isc_buffer_used(text),
8207 		     isc_buffer_availablelength(text),
8208 		     "version: %s%s%s%s <id:%s>\n"
8209 		     "boot time: %s\n"
8210 		     "last configured: %s\n"
8211 #ifdef ISC_PLATFORM_USETHREADS
8212 		     "CPUs found: %u\n"
8213 		     "worker threads: %u\n"
8214 		     "UDP listeners per interface: %u\n"
8215 #endif
8216 		     "number of zones: %u\n"
8217 		     "debug level: %d\n"
8218 		     "xfers running: %u\n"
8219 		     "xfers deferred: %u\n"
8220 		     "soa queries in progress: %u\n"
8221 		     "query logging is %s\n"
8222 		     "recursive clients: %d/%d/%d\n"
8223 		     "tcp clients: %d/%d\n"
8224 		     "server is up and running",
8225 		     ns_g_version, ob, alt, cb, ns_g_srcid,
8226 		     boottime, configtime,
8227 #ifdef ISC_PLATFORM_USETHREADS
8228 		     ns_g_cpus_detected, ns_g_cpus, ns_g_udpdisp,
8229 #endif
8230 		     zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
8231 		     soaqueries, server->log_queries ? "ON" : "OFF",
8232 		     server->recursionquota.used, server->recursionquota.soft,
8233 		     server->recursionquota.max,
8234 		     server->tcpquota.used, server->tcpquota.max);
8235 	if (n >= isc_buffer_availablelength(text))
8236 		return (ISC_R_NOSPACE);
8237 	isc_buffer_add(text, n);
8238 	return (ISC_R_SUCCESS);
8239 }
8240 
8241 static isc_result_t
8242 delete_keynames(dns_tsig_keyring_t *ring, char *target,
8243 		unsigned int *foundkeys)
8244 {
8245 	char namestr[DNS_NAME_FORMATSIZE];
8246 	isc_result_t result;
8247 	dns_rbtnodechain_t chain;
8248 	dns_name_t foundname;
8249 	dns_fixedname_t fixedorigin;
8250 	dns_name_t *origin;
8251 	dns_rbtnode_t *node;
8252 	dns_tsigkey_t *tkey;
8253 
8254 	dns_name_init(&foundname, NULL);
8255 	dns_fixedname_init(&fixedorigin);
8256 	origin = dns_fixedname_name(&fixedorigin);
8257 
8258  again:
8259 	dns_rbtnodechain_init(&chain, ring->mctx);
8260 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
8261 					origin);
8262 	if (result == ISC_R_NOTFOUND) {
8263 		dns_rbtnodechain_invalidate(&chain);
8264 		return (ISC_R_SUCCESS);
8265 	}
8266 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
8267 		dns_rbtnodechain_invalidate(&chain);
8268 		return (result);
8269 	}
8270 
8271 	for (;;) {
8272 		node = NULL;
8273 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
8274 		tkey = node->data;
8275 
8276 		if (tkey != NULL) {
8277 			if (!tkey->generated)
8278 				goto nextkey;
8279 
8280 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
8281 			if (strcmp(namestr, target) == 0) {
8282 				(*foundkeys)++;
8283 				dns_rbtnodechain_invalidate(&chain);
8284 				(void)dns_rbt_deletename(ring->keys,
8285 							 &tkey->name,
8286 							 ISC_FALSE);
8287 				goto again;
8288 			}
8289 		}
8290 
8291 	nextkey:
8292 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
8293 		if (result == ISC_R_NOMORE)
8294 			break;
8295 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
8296 			dns_rbtnodechain_invalidate(&chain);
8297 			return (result);
8298 		}
8299 	}
8300 
8301 	return (ISC_R_SUCCESS);
8302 }
8303 
8304 isc_result_t
8305 ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
8306 	isc_result_t result;
8307 	unsigned int n;
8308 	dns_view_t *view;
8309 	unsigned int foundkeys = 0;
8310 	char *target;
8311 	char *viewname;
8312 
8313 	(void)next_token(&command, " \t");  /* skip command name */
8314 	target = next_token(&command, " \t");
8315 	if (target == NULL)
8316 		return (ISC_R_UNEXPECTEDEND);
8317 	viewname = next_token(&command, " \t");
8318 
8319 	result = isc_task_beginexclusive(server->task);
8320 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8321 	for (view = ISC_LIST_HEAD(server->viewlist);
8322 	     view != NULL;
8323 	     view = ISC_LIST_NEXT(view, link)) {
8324 		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
8325 			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
8326 			result = delete_keynames(view->dynamickeys, target,
8327 						 &foundkeys);
8328 			RWUNLOCK(&view->dynamickeys->lock,
8329 				 isc_rwlocktype_write);
8330 			if (result != ISC_R_SUCCESS) {
8331 				isc_task_endexclusive(server->task);
8332 				return (result);
8333 			}
8334 		}
8335 	}
8336 	isc_task_endexclusive(server->task);
8337 
8338 	n = snprintf((char *)isc_buffer_used(text),
8339 		     isc_buffer_availablelength(text),
8340 		     "%d tsig keys deleted.\n", foundkeys);
8341 	if (n >= isc_buffer_availablelength(text))
8342 		return (ISC_R_NOSPACE);
8343 	isc_buffer_add(text, n);
8344 
8345 	return (ISC_R_SUCCESS);
8346 }
8347 
8348 static isc_result_t
8349 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
8350 	     unsigned int *foundkeys)
8351 {
8352 	char namestr[DNS_NAME_FORMATSIZE];
8353 	char creatorstr[DNS_NAME_FORMATSIZE];
8354 	isc_result_t result;
8355 	dns_rbtnodechain_t chain;
8356 	dns_name_t foundname;
8357 	dns_fixedname_t fixedorigin;
8358 	dns_name_t *origin;
8359 	dns_rbtnode_t *node;
8360 	dns_tsigkey_t *tkey;
8361 	const char *viewname;
8362 
8363 	if (view != NULL)
8364 		viewname = view->name;
8365 	else
8366 		viewname = "(global)";
8367 
8368 	dns_name_init(&foundname, NULL);
8369 	dns_fixedname_init(&fixedorigin);
8370 	origin = dns_fixedname_name(&fixedorigin);
8371 	dns_rbtnodechain_init(&chain, ring->mctx);
8372 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
8373 					origin);
8374 	if (result == ISC_R_NOTFOUND) {
8375 		dns_rbtnodechain_invalidate(&chain);
8376 		return (ISC_R_SUCCESS);
8377 	}
8378 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
8379 		dns_rbtnodechain_invalidate(&chain);
8380 		return (result);
8381 	}
8382 
8383 	for (;;) {
8384 		node = NULL;
8385 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
8386 		tkey = node->data;
8387 
8388 		if (tkey != NULL) {
8389 			(*foundkeys)++;
8390 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
8391 			if (tkey->generated) {
8392 				dns_name_format(tkey->creator, creatorstr,
8393 						sizeof(creatorstr));
8394 				if (*foundkeys != 0)
8395 					CHECK(putstr(text, "\n"));
8396 				CHECK(putstr(text, "view \""));
8397 				CHECK(putstr(text, viewname));
8398 				CHECK(putstr(text,
8399 					     "\"; type \"dynamic\"; key \""));
8400 				CHECK(putstr(text, namestr));
8401 				CHECK(putstr(text, "\"; creator \""));
8402 				CHECK(putstr(text, creatorstr));
8403 				CHECK(putstr(text, "\";"));
8404 			} else {
8405 				if (*foundkeys != 0)
8406 					CHECK(putstr(text, "\n"));
8407 				CHECK(putstr(text, "view \""));
8408 				CHECK(putstr(text, viewname));
8409 				CHECK(putstr(text,
8410 					     "\"; type \"static\"; key \""));
8411 				CHECK(putstr(text, namestr));
8412 				CHECK(putstr(text, "\";"));
8413 			}
8414 		}
8415 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
8416 		if (result == ISC_R_NOMORE)
8417 			break;
8418 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
8419 			dns_rbtnodechain_invalidate(&chain);
8420 			return (result);
8421 		}
8422 	}
8423 
8424 	return (ISC_R_SUCCESS);
8425 
8426 cleanup:
8427 	return (result);
8428 }
8429 
8430 isc_result_t
8431 ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
8432 	isc_result_t result;
8433 	dns_view_t *view;
8434 	unsigned int foundkeys = 0;
8435 
8436 	result = isc_task_beginexclusive(server->task);
8437 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8438 	for (view = ISC_LIST_HEAD(server->viewlist);
8439 	     view != NULL;
8440 	     view = ISC_LIST_NEXT(view, link)) {
8441 		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
8442 		result = list_keynames(view, view->statickeys, text,
8443 				       &foundkeys);
8444 		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
8445 		if (result != ISC_R_SUCCESS) {
8446 			isc_task_endexclusive(server->task);
8447 			return (result);
8448 		}
8449 		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
8450 		result = list_keynames(view, view->dynamickeys, text,
8451 				       &foundkeys);
8452 		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
8453 		if (result != ISC_R_SUCCESS) {
8454 			isc_task_endexclusive(server->task);
8455 			return (result);
8456 		}
8457 	}
8458 	isc_task_endexclusive(server->task);
8459 
8460 	if (foundkeys == 0)
8461 		CHECK(putstr(text, "no tsig keys found."));
8462 
8463 	if (isc_buffer_usedlength(text) > 0)
8464 		CHECK(putnull(text));
8465 
8466 	return (ISC_R_SUCCESS);
8467 
8468  cleanup:
8469 	return (result);
8470 }
8471 
8472 /*
8473  * Act on a "sign" or "loadkeys" command from the command channel.
8474  */
8475 isc_result_t
8476 ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text) {
8477 	isc_result_t result;
8478 	dns_zone_t *zone = NULL;
8479 	dns_zonetype_t type;
8480 	isc_uint16_t keyopts;
8481 	isc_boolean_t fullsign = ISC_FALSE;
8482 
8483 	if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
8484 	    fullsign = ISC_TRUE;
8485 
8486 	result = zone_from_args(server, args, NULL, &zone, NULL,
8487 				text, ISC_TRUE);
8488 	if (result != ISC_R_SUCCESS)
8489 		return (result);
8490 	if (zone == NULL)
8491 		return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
8492 
8493 	type = dns_zone_gettype(zone);
8494 	if (type != dns_zone_master) {
8495 		dns_zone_detach(&zone);
8496 		return (DNS_R_NOTMASTER);
8497 	}
8498 
8499 	keyopts = dns_zone_getkeyopts(zone);
8500 
8501 	/* "rndc loadkeys" requires "auto-dnssec maintain". */
8502 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
8503 		result = ISC_R_NOPERM;
8504 	else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
8505 		result = ISC_R_NOPERM;
8506 	else
8507 		dns_zone_rekey(zone, fullsign);
8508 
8509 	dns_zone_detach(&zone);
8510 	return (result);
8511 }
8512 
8513 /*
8514  * Act on a "sync" command from the command channel.
8515 */
8516 static isc_result_t
8517 synczone(dns_zone_t *zone, void *uap) {
8518 	isc_boolean_t cleanup = *(isc_boolean_t *)uap;
8519 	isc_result_t result;
8520 	dns_zone_t *raw = NULL;
8521 	char *journal;
8522 
8523 	dns_zone_getraw(zone, &raw);
8524 	if (raw != NULL) {
8525 		synczone(raw, uap);
8526 		dns_zone_detach(&raw);
8527 	}
8528 
8529 	result = dns_zone_flush(zone);
8530 	if (result != ISC_R_SUCCESS)
8531 		cleanup = ISC_FALSE;
8532 	if (cleanup) {
8533 		journal = dns_zone_getjournal(zone);
8534 		if (journal != NULL)
8535 			(void)isc_file_remove(journal);
8536 	}
8537 
8538 	return (result);
8539 }
8540 
8541 isc_result_t
8542 ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
8543 	isc_result_t result, tresult;
8544 	dns_view_t *view;
8545 	dns_zone_t *zone = NULL;
8546 	char classstr[DNS_RDATACLASS_FORMATSIZE];
8547 	char zonename[DNS_NAME_FORMATSIZE];
8548 	const char *vname, *sep, *msg = NULL, *arg;
8549 	isc_boolean_t cleanup = ISC_FALSE;
8550 
8551 	(void) next_token(&args, " \t");
8552 
8553 	arg = next_token(&args, " \t");
8554 	if (arg != NULL &&
8555 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
8556 		cleanup = ISC_TRUE;
8557 		arg = next_token(&args, " \t");
8558 	}
8559 
8560 	result = zone_from_args(server, args, arg, &zone, NULL,
8561 				text, ISC_FALSE);
8562 	if (result != ISC_R_SUCCESS)
8563 		return (result);
8564 
8565 	if (zone == NULL) {
8566 		result = isc_task_beginexclusive(server->task);
8567 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8568 		tresult = ISC_R_SUCCESS;
8569 		for (view = ISC_LIST_HEAD(server->viewlist);
8570 		     view != NULL;
8571 		     view = ISC_LIST_NEXT(view, link)) {
8572 			result = dns_zt_apply(view->zonetable, ISC_FALSE,
8573 					      synczone, &cleanup);
8574 			if (result != ISC_R_SUCCESS &&
8575 			    tresult == ISC_R_SUCCESS)
8576 				tresult = result;
8577 		}
8578 		isc_task_endexclusive(server->task);
8579 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8580 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8581 			      "dumping all zones%s: %s",
8582 			      cleanup ? ", removing journal files" : "",
8583 			      isc_result_totext(result));
8584 		return (tresult);
8585 	}
8586 
8587 	result = isc_task_beginexclusive(server->task);
8588 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8589 	result = synczone(zone, &cleanup);
8590 	isc_task_endexclusive(server->task);
8591 
8592 	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
8593 		isc_buffer_putmem(text, (const unsigned char *)msg,
8594 				  strlen(msg) + 1);
8595 
8596 	view = dns_zone_getview(zone);
8597 	if (strcmp(view->name, "_default") == 0 ||
8598 	    strcmp(view->name, "_bind") == 0)
8599 	{
8600 		vname = "";
8601 		sep = "";
8602 	} else {
8603 		vname = view->name;
8604 		sep = " ";
8605 	}
8606 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
8607 			      sizeof(classstr));
8608 	dns_name_format(dns_zone_getorigin(zone),
8609 			zonename, sizeof(zonename));
8610 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8611 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8612 		      "sync: dumping zone '%s/%s'%s%s%s: %s",
8613 		      zonename, classstr, sep, vname,
8614 		      cleanup ? ", removing journal file" : "",
8615 		      isc_result_totext(result));
8616 	dns_zone_detach(&zone);
8617 	return (result);
8618 }
8619 
8620 /*
8621  * Act on a "freeze" or "thaw" command from the command channel.
8622  */
8623 isc_result_t
8624 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
8625 		 isc_buffer_t *text)
8626 {
8627 	isc_result_t result, tresult;
8628 	dns_zone_t *zone = NULL, *raw = NULL;
8629 	dns_zonetype_t type;
8630 	char classstr[DNS_RDATACLASS_FORMATSIZE];
8631 	char zonename[DNS_NAME_FORMATSIZE];
8632 	dns_view_t *view;
8633 	const char *vname, *sep;
8634 	isc_boolean_t frozen;
8635 	const char *msg = NULL;
8636 
8637 	result = zone_from_args(server, args, NULL, &zone, NULL,
8638 				text, ISC_TRUE);
8639 	if (result != ISC_R_SUCCESS)
8640 		return (result);
8641 	if (zone == NULL) {
8642 		result = isc_task_beginexclusive(server->task);
8643 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8644 		tresult = ISC_R_SUCCESS;
8645 		for (view = ISC_LIST_HEAD(server->viewlist);
8646 		     view != NULL;
8647 		     view = ISC_LIST_NEXT(view, link)) {
8648 			result = dns_view_freezezones(view, freeze);
8649 			if (result != ISC_R_SUCCESS &&
8650 			    tresult == ISC_R_SUCCESS)
8651 				tresult = result;
8652 		}
8653 		isc_task_endexclusive(server->task);
8654 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8655 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8656 			      "%s all zones: %s",
8657 			      freeze ? "freezing" : "thawing",
8658 			      isc_result_totext(tresult));
8659 		return (tresult);
8660 	}
8661 	dns_zone_getraw(zone, &raw);
8662 	if (raw != NULL) {
8663 		dns_zone_detach(&zone);
8664 		dns_zone_attach(raw, &zone);
8665 		dns_zone_detach(&raw);
8666 	}
8667 	type = dns_zone_gettype(zone);
8668 	if (type != dns_zone_master) {
8669 		dns_zone_detach(&zone);
8670 		return (DNS_R_NOTMASTER);
8671 	}
8672 
8673 	if (freeze && !dns_zone_isdynamic(zone, ISC_TRUE)) {
8674 		dns_zone_detach(&zone);
8675 		return (DNS_R_NOTDYNAMIC);
8676 	}
8677 
8678 	result = isc_task_beginexclusive(server->task);
8679 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8680 	frozen = dns_zone_getupdatedisabled(zone);
8681 	if (freeze) {
8682 		if (frozen) {
8683 			msg = "WARNING: The zone was already frozen.\n"
8684 			      "Someone else may be editing it or "
8685 			      "it may still be re-loading.";
8686 			result = DNS_R_FROZEN;
8687 		}
8688 		if (result == ISC_R_SUCCESS) {
8689 			result = dns_zone_flush(zone);
8690 			if (result != ISC_R_SUCCESS)
8691 				msg = "Flushing the zone updates to "
8692 				      "disk failed.";
8693 		}
8694 		if (result == ISC_R_SUCCESS)
8695 			dns_zone_setupdatedisabled(zone, freeze);
8696 	} else {
8697 		if (frozen) {
8698 			result = dns_zone_loadandthaw(zone);
8699 			switch (result) {
8700 			case ISC_R_SUCCESS:
8701 			case DNS_R_UPTODATE:
8702 				msg = "The zone reload and thaw was "
8703 				      "successful.";
8704 				result = ISC_R_SUCCESS;
8705 				break;
8706 			case DNS_R_CONTINUE:
8707 				msg = "A zone reload and thaw was started.\n"
8708 				      "Check the logs to see the result.";
8709 				result = ISC_R_SUCCESS;
8710 				break;
8711 			}
8712 		}
8713 	}
8714 	isc_task_endexclusive(server->task);
8715 
8716 	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
8717 		isc_buffer_putmem(text, (const unsigned char *)msg,
8718 				  strlen(msg) + 1);
8719 
8720 	view = dns_zone_getview(zone);
8721 	if (strcmp(view->name, "_default") == 0 ||
8722 	    strcmp(view->name, "_bind") == 0)
8723 	{
8724 		vname = "";
8725 		sep = "";
8726 	} else {
8727 		vname = view->name;
8728 		sep = " ";
8729 	}
8730 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
8731 			      sizeof(classstr));
8732 	dns_name_format(dns_zone_getorigin(zone),
8733 			zonename, sizeof(zonename));
8734 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8735 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8736 		      "%s zone '%s/%s'%s%s: %s",
8737 		      freeze ? "freezing" : "thawing",
8738 		      zonename, classstr, sep, vname,
8739 		      isc_result_totext(result));
8740 	dns_zone_detach(&zone);
8741 	return (result);
8742 }
8743 
8744 #ifdef HAVE_LIBSCF
8745 /*
8746  * This function adds a message for rndc to echo if named
8747  * is managed by smf and is also running chroot.
8748  */
8749 isc_result_t
8750 ns_smf_add_message(isc_buffer_t *text) {
8751 	unsigned int n;
8752 
8753 	n = snprintf((char *)isc_buffer_used(text),
8754 		isc_buffer_availablelength(text),
8755 		"use svcadm(1M) to manage named");
8756 	if (n >= isc_buffer_availablelength(text))
8757 		return (ISC_R_NOSPACE);
8758 	isc_buffer_add(text, n);
8759 	return (ISC_R_SUCCESS);
8760 }
8761 #endif /* HAVE_LIBSCF */
8762 
8763 /*
8764  * Emit a comment at the top of the nzf file containing the viewname
8765  * Expects the fp to already be open for writing
8766  */
8767 #define HEADER1 "# New zone file for view: "
8768 #define HEADER2 "\n# This file contains configuration for zones added by\n" \
8769 		"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
8770 isc_result_t
8771 add_comment(FILE *fp, const char *viewname) {
8772 	isc_result_t result;
8773 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
8774 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
8775 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
8776  cleanup:
8777 	return (result);
8778 }
8779 
8780 /*
8781  * Act on an "addzone" command from the command channel.
8782  */
8783 isc_result_t
8784 ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
8785 	isc_result_t	     result, tresult;
8786 	isc_buffer_t	     argbuf;
8787 	size_t		     arglen;
8788 	cfg_parser_t	    *parser = NULL;
8789 	cfg_obj_t	    *config = NULL;
8790 	const cfg_obj_t	    *vconfig = NULL;
8791 	const cfg_obj_t	    *views = NULL;
8792 	const cfg_obj_t     *parms = NULL;
8793 	const cfg_obj_t     *obj = NULL;
8794 	const cfg_listelt_t *element;
8795 	const char	    *zonename;
8796 	const char	    *classname = NULL;
8797 	const char	    *argp;
8798 	const char	    *viewname = NULL;
8799 	dns_rdataclass_t     rdclass;
8800 	dns_view_t	    *view = NULL;
8801 	isc_buffer_t	     buf;
8802 	dns_fixedname_t	     fname;
8803 	dns_name_t	    *dnsname;
8804 	dns_zone_t	    *zone = NULL;
8805 	FILE		    *fp = NULL;
8806 	struct cfg_context  *cfg = NULL;
8807 	char 		    namebuf[DNS_NAME_FORMATSIZE];
8808 	off_t		    offset;
8809 
8810 	/* Try to parse the argument string */
8811 	arglen = strlen(args);
8812 	isc_buffer_init(&argbuf, args, (unsigned int)arglen);
8813 	isc_buffer_add(&argbuf, strlen(args));
8814 	CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser));
8815 	CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf,
8816 			       &config));
8817 	CHECK(cfg_map_get(config, "addzone", &parms));
8818 
8819 	zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
8820 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
8821 	isc_buffer_add(&buf, strlen(zonename));
8822 
8823 	dns_fixedname_init(&fname);
8824 	dnsname = dns_fixedname_name(&fname);
8825 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
8826 
8827 	/* Make sense of optional class argument */
8828 	obj = cfg_tuple_get(parms, "class");
8829 	CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
8830 	if (rdclass != dns_rdataclass_in && obj)
8831 		classname = cfg_obj_asstring(obj);
8832 
8833 	/* Make sense of optional view argument */
8834 	obj = cfg_tuple_get(parms, "view");
8835 	if (obj && cfg_obj_isstring(obj))
8836 		viewname = cfg_obj_asstring(obj);
8837 	if (viewname == NULL || *viewname == '\0')
8838 		viewname = "_default";
8839 	CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
8840 
8841 	/* Are we accepting new zones? */
8842 	if (view->new_zone_file == NULL) {
8843 		result = ISC_R_NOPERM;
8844 		goto cleanup;
8845 	}
8846 
8847 	cfg = (struct cfg_context *) view->new_zone_config;
8848 	if (cfg == NULL) {
8849 		result = ISC_R_FAILURE;
8850 		goto cleanup;
8851 	}
8852 
8853 	/* Zone shouldn't already exist */
8854 	result = dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone);
8855 	if (result == ISC_R_SUCCESS) {
8856 		result = ISC_R_EXISTS;
8857 		goto cleanup;
8858 	} else if (result == DNS_R_PARTIALMATCH) {
8859 		/* Create our sub-zone anyway */
8860 		dns_zone_detach(&zone);
8861 		zone = NULL;
8862 	}
8863 	else if (result != ISC_R_NOTFOUND)
8864 		goto cleanup;
8865 
8866 	/* Find the view statement */
8867 	cfg_map_get(cfg->config, "view", &views);
8868 	for (element = cfg_list_first(views);
8869 	     element != NULL;
8870 	     element = cfg_list_next(element))
8871 	{
8872 		const char *vname;
8873 		vconfig = cfg_listelt_value(element);
8874 		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
8875 		if (vname && !strcasecmp(vname, viewname))
8876 			break;
8877 		vconfig = NULL;
8878 	}
8879 
8880 	/* Open save file for write configuration */
8881 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
8882 	if (result != ISC_R_SUCCESS) {
8883 		TCHECK(putstr(text, "unable to open '"));
8884 		TCHECK(putstr(text, view->new_zone_file));
8885 		TCHECK(putstr(text, "': "));
8886 		TCHECK(putstr(text, isc_result_totext(result)));
8887 		goto cleanup;
8888 	}
8889 	CHECK(isc_stdio_tell(fp, &offset));
8890 	if (offset == 0)
8891 		CHECK(add_comment(fp, view->name));
8892 
8893 	/* Mark view unfrozen so that zone can be added */
8894 	result = isc_task_beginexclusive(server->task);
8895 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
8896 	dns_view_thaw(view);
8897 	result = configure_zone(cfg->config, parms, vconfig,
8898 				server->mctx, view, NULL, cfg->actx,
8899 				ISC_FALSE, ISC_FALSE);
8900 	dns_view_freeze(view);
8901 	isc_task_endexclusive(server->task);
8902 	if (result != ISC_R_SUCCESS) {
8903 		TCHECK(putstr(text, "configure_zone failed: "));
8904 		TCHECK(putstr(text, isc_result_totext(result)));
8905 		goto cleanup;
8906 	}
8907 
8908 	/* Is it there yet? */
8909 	CHECK(dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone));
8910 
8911 	/*
8912 	 * Load the zone from the master file.  If this fails, we'll
8913 	 * need to undo the configuration we've done already.
8914 	 */
8915 	result = dns_zone_loadnew(zone);
8916 	if (result != ISC_R_SUCCESS) {
8917 		dns_db_t *dbp = NULL;
8918 
8919 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
8920 		TCHECK(putstr(text, isc_result_totext(result)));
8921 
8922 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8923 			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8924 			      "addzone failed; reverting.");
8925 
8926 		/* If the zone loaded partially, unload it */
8927 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
8928 			dns_db_detach(&dbp);
8929 			dns_zone_unload(zone);
8930 		}
8931 
8932 		/* Remove the zone from the zone table */
8933 		dns_zt_unmount(view->zonetable, zone);
8934 		goto cleanup;
8935 	}
8936 
8937 	/* Flag the zone as having been added at runtime */
8938 	dns_zone_setadded(zone, ISC_TRUE);
8939 
8940 	/* Emit the zone name, quoted and escaped */
8941 	isc_buffer_init(&buf, namebuf, sizeof(namebuf));
8942 	CHECK(dns_name_totext(dnsname, ISC_TRUE, &buf));
8943 	putnull(&buf);
8944 	CHECK(isc_stdio_write("zone \"", 6, 1, fp, NULL));
8945 	CHECK(isc_stdio_write(namebuf, strlen(namebuf), 1, fp, NULL));
8946 	CHECK(isc_stdio_write("\" ", 2, 1, fp, NULL));
8947 
8948 	/* Classname, if not default */
8949 	if (classname != NULL && *classname != '\0') {
8950 		CHECK(isc_stdio_write(classname, strlen(classname), 1, fp,
8951 				      NULL));
8952 		CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
8953 	}
8954 
8955 	/* Find beginning of option block from args */
8956 	for (argp = args; *argp; argp++, arglen--) {
8957 		if (*argp == '{') {	/* Assume matching '}' */
8958 			/* Add that to our file */
8959 			CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL));
8960 
8961 			/* Make sure we end with a LF */
8962 			if (argp[arglen-1] != '\n') {
8963 				CHECK(isc_stdio_write("\n", 1, 1, fp, NULL));
8964 			}
8965 			break;
8966 		}
8967 	}
8968 
8969 	CHECK(isc_stdio_close(fp));
8970 	fp = NULL;
8971 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8972 				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8973 				  "zone %s added to view %s via addzone",
8974 				  zonename, viewname);
8975 
8976 	/* Adding a zone counts as reconfiguration */
8977 	CHECK(isc_time_now(&ns_g_configtime));
8978 
8979 	result = ISC_R_SUCCESS;
8980 
8981  cleanup:
8982 	if (isc_buffer_usedlength(text) > 0)
8983 		putnull(text);
8984 	if (fp != NULL)
8985 		isc_stdio_close(fp);
8986 	if (parser != NULL) {
8987 		if (config != NULL)
8988 			cfg_obj_destroy(parser, &config);
8989 		cfg_parser_destroy(&parser);
8990 	}
8991 	if (zone != NULL)
8992 		dns_zone_detach(&zone);
8993 	if (view != NULL)
8994 		dns_view_detach(&view);
8995 
8996 	return (result);
8997 }
8998 
8999 static isc_boolean_t
9000 inuse(const char* file, isc_boolean_t first, isc_buffer_t *text) {
9001 #define INUSEMSG "The following files were in use and may now be removed:\n"
9002 
9003 	if (file != NULL && isc_file_exists(file) &&
9004 	    isc_buffer_availablelength(text) >
9005 	    strlen(file) + (first ? sizeof(INUSEMSG) : sizeof("\n")))
9006 	{
9007 		if (first)
9008 			(void) putstr(text, INUSEMSG);
9009 		else
9010 			(void) putstr(text, "\n");
9011 		(void) putstr(text, file);
9012 		return (ISC_FALSE);
9013 	}
9014 	return (first);
9015 }
9016 
9017 /*
9018  * Act on a "delzone" command from the command channel.
9019  */
9020 isc_result_t
9021 ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
9022 	isc_result_t result;
9023 	dns_zone_t *zone = NULL;
9024 	dns_zone_t *raw = NULL;
9025 	dns_zone_t *mayberaw;
9026 	dns_view_t *view = NULL;
9027 	dns_db_t *dbp = NULL;
9028 	const char *filename = NULL;
9029 	char *tmpname = NULL;
9030 	char buf[1024];
9031 	const char *zonename = NULL;
9032 	size_t znamelen = 0;
9033 	FILE *ifp = NULL, *ofp = NULL;
9034 	isc_boolean_t exclusive = ISC_FALSE;
9035 	isc_boolean_t cleanup = ISC_FALSE;
9036 	isc_boolean_t inheader = ISC_TRUE;
9037 	const char *file, *arg;
9038 
9039 	/* Parse parameters */
9040 	(void) next_token(&args, " \t");
9041 	arg = next_token(&args, " \t");
9042 	if (arg != NULL &&
9043 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
9044 		cleanup = ISC_TRUE;
9045 		arg = next_token(&args, " \t");
9046 	}
9047 
9048 	CHECK(zone_from_args(server, args, arg, &zone, &zonename,
9049 			     text, ISC_FALSE));
9050 	if (zone == NULL) {
9051 		result = ISC_R_UNEXPECTEDEND;
9052 		goto cleanup;
9053 	}
9054 
9055 	result = isc_task_beginexclusive(server->task);
9056 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9057 	exclusive = ISC_TRUE;
9058 
9059 	/*
9060 	 * Was this zone originally added at runtime?
9061 	 * If not, we can't delete it now.
9062 	 */
9063 	if (!dns_zone_getadded(zone)) {
9064 		result = ISC_R_NOPERM;
9065 		goto cleanup;
9066 	}
9067 
9068 	INSIST(zonename != NULL);
9069 	znamelen = strlen(zonename);
9070 
9071 	/* Dig out configuration for this zone */
9072 	view = dns_zone_getview(zone);
9073 	filename = view->new_zone_file;
9074 	if (filename == NULL) {
9075 		/* No adding zones in this view */
9076 		result = ISC_R_FAILURE;
9077 		goto cleanup;
9078 	}
9079 
9080 	/* Rewrite zone list */
9081 	result = isc_stdio_open(filename, "r", &ifp);
9082 	if (ifp != NULL && result == ISC_R_SUCCESS) {
9083 		char *found = NULL, *p = NULL;
9084 		size_t n;
9085 
9086 		/* Create a temporary file */
9087 		CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename,
9088 					(long)getpid()));
9089 		if (!(tmpname = isc_mem_strdup(server->mctx, buf))) {
9090 			result = ISC_R_NOMEMORY;
9091 			goto cleanup;
9092 		}
9093 		CHECK(isc_stdio_open(tmpname, "w", &ofp));
9094 		CHECK(add_comment(ofp, view->name));
9095 
9096 		/* Look for the entry for that zone */
9097 		while (fgets(buf, 1024, ifp)) {
9098 			/* Skip initial comment, if any */
9099 			if (inheader && *buf == '#')
9100 				continue;
9101 			if (*buf != '#')
9102 				inheader = ISC_FALSE;
9103 
9104 			/*
9105 			 * Any other lines not starting with zone, copy
9106 			 * them out and continue.
9107 			 */
9108 			if (strncasecmp(buf, "zone", 4) != 0) {
9109 				fputs(buf, ofp);
9110 				continue;
9111 			}
9112 			p = buf+4;
9113 
9114 			/* This is a zone; find its name. */
9115 			while (*p &&
9116 			       ((*p == '"') || isspace((unsigned char)*p)))
9117 				p++;
9118 
9119 			/*
9120 			 * If it's not the zone we're looking for, copy
9121 			 * it out and continue
9122 			 */
9123 			if (strncasecmp(p, zonename, znamelen) != 0) {
9124 				fputs(buf, ofp);
9125 				continue;
9126 			}
9127 
9128 			/*
9129 			 * But if it is the zone we want, skip over it
9130 			 * so it will be omitted from the new file
9131 			 */
9132 			p += znamelen;
9133 			if (isspace((unsigned char)*p) ||
9134 			    *p == '"' || *p == '{') {
9135 				/* This must be the entry */
9136 				found = p;
9137 				break;
9138 			}
9139 
9140 			/* Copy the rest of the buffer out and continue */
9141 			fputs(buf, ofp);
9142 		}
9143 
9144 		/* Skip over an option block (matching # of braces) */
9145 		if (found) {
9146 			int obrace = 0, cbrace = 0;
9147 			for (;;) {
9148 				while (*p) {
9149 					if (*p == '{') obrace++;
9150 					if (*p == '}') cbrace++;
9151 					p++;
9152 				}
9153 				if (obrace && (obrace == cbrace))
9154 					break;
9155 				if (!fgets(buf, 1024, ifp))
9156 					break;
9157 				p = buf;
9158 			}
9159 
9160 			/* Just spool the remainder of the file out */
9161 			result = isc_stdio_read(buf, 1, 1024, ifp, &n);
9162 			while (n > 0U) {
9163 				if (result == ISC_R_EOF)
9164 					result = ISC_R_SUCCESS;
9165 				CHECK(result);
9166 				isc_stdio_write(buf, 1, n, ofp, NULL);
9167 				result = isc_stdio_read(buf, 1, 1024, ifp, &n);
9168 			}
9169 
9170 			/*
9171 			 * Close files before overwriting the nzfile
9172 			 * with the temporary file as it's necessary on
9173 			 * some platforms (win32).
9174 			 */
9175 			(void) isc_stdio_close(ifp);
9176 			ifp = NULL;
9177 			(void) isc_stdio_close(ofp);
9178 			ofp = NULL;
9179 
9180 			/* Move temporary into place */
9181 			CHECK(isc_file_rename(tmpname, view->new_zone_file));
9182 		} else {
9183 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
9184 				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
9185 				      "deleted zone %s was missing from "
9186 				      "new zone file", zonename);
9187 			goto cleanup;
9188 		}
9189 	}
9190 
9191 	/* Stop answering for this zone */
9192 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
9193 		dns_db_detach(&dbp);
9194 		dns_zone_unload(zone);
9195 	}
9196 
9197 	/* Clean up stub / slave zone files */
9198 	dns_zone_getraw(zone, &raw);
9199 	mayberaw = (raw != NULL) ? raw : zone;
9200 	if (cleanup) {
9201 		isc_result_t tresult;
9202 
9203 		file = dns_zone_getfile(mayberaw);
9204 		if (isc_file_exists(file))
9205 			isc_file_remove(file);
9206 
9207 		file = dns_zone_getjournal(mayberaw);
9208 		if (isc_file_exists(file))
9209 			isc_file_remove(file);
9210 
9211 		if (zone != mayberaw) {
9212 			file = dns_zone_getfile(zone);
9213 			if (isc_file_exists(file))
9214 				isc_file_remove(file);
9215 
9216 			file = dns_zone_getjournal(zone);
9217 			if (isc_file_exists(file))
9218 				isc_file_remove(file);
9219 		}
9220 		TCHECK(putstr(text, "zone "));
9221 		TCHECK(putstr(text, zonename));
9222 		TCHECK(putstr(text, " and associated files deleted"));
9223 		TCHECK(putnull(text));
9224 	} else if (dns_zone_gettype(mayberaw) == dns_zone_slave ||
9225 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
9226 	{
9227 		isc_boolean_t first;
9228 
9229 		file = dns_zone_getfile(mayberaw);
9230 		first = inuse(file, ISC_TRUE, text);
9231 
9232 		file = dns_zone_getjournal(mayberaw);
9233 		first = inuse(file, first, text);
9234 
9235 		if (zone != mayberaw) {
9236 			file = dns_zone_getfile(zone);
9237 			first = inuse(file, first, text);
9238 
9239 			file = dns_zone_getjournal(zone);
9240 			(void)inuse(file, first, text);
9241 		}
9242 		putnull(text);
9243 	}
9244 
9245 	CHECK(dns_zt_unmount(view->zonetable, zone));
9246 
9247 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
9248 				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
9249 				  "zone %s removed via delzone", zonename);
9250 
9251 	/* Removing a zone counts as reconfiguration */
9252 	CHECK(isc_time_now(&ns_g_configtime));
9253 
9254 	result = ISC_R_SUCCESS;
9255 
9256  cleanup:
9257 	if (isc_buffer_usedlength(text) > 0)
9258 		putnull(text);
9259 	if (exclusive)
9260 		isc_task_endexclusive(server->task);
9261 	if (ifp != NULL)
9262 		isc_stdio_close(ifp);
9263 	if (ofp != NULL)
9264 		isc_stdio_close(ofp);
9265 	if (tmpname != NULL) {
9266 		isc_file_remove(tmpname);
9267 		isc_mem_free(server->mctx, tmpname);
9268 	}
9269 	if (raw != NULL)
9270 		dns_zone_detach(&raw);
9271 	if (zone != NULL)
9272 		dns_zone_detach(&zone);
9273 
9274 	return (result);
9275 }
9276 
9277 static void
9278 newzone_cfgctx_destroy(void **cfgp) {
9279 	struct cfg_context *cfg;
9280 
9281 	REQUIRE(cfgp != NULL && *cfgp != NULL);
9282 
9283 	cfg = *cfgp;
9284 
9285 	if (cfg->actx != NULL)
9286 		cfg_aclconfctx_detach(&cfg->actx);
9287 
9288 	if (cfg->parser != NULL) {
9289 		if (cfg->config != NULL)
9290 			cfg_obj_destroy(cfg->parser, &cfg->config);
9291 		cfg_parser_destroy(&cfg->parser);
9292 	}
9293 	if (cfg->nzparser != NULL) {
9294 		if (cfg->nzconfig != NULL)
9295 			cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig);
9296 		cfg_parser_destroy(&cfg->nzparser);
9297 	}
9298 
9299 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
9300 	*cfgp = NULL;
9301 }
9302 
9303 static isc_result_t
9304 generate_salt(unsigned char *salt, size_t saltlen) {
9305 	int i, n;
9306 	union {
9307 		unsigned char rnd[256];
9308 		isc_uint32_t rnd32[64];
9309 	} rnd;
9310 	unsigned char text[512 + 1];
9311 	isc_region_t r;
9312 	isc_buffer_t buf;
9313 	isc_result_t result;
9314 
9315 	if (saltlen > 256U)
9316 		return (ISC_R_RANGE);
9317 
9318 	n = (int) (saltlen + sizeof(isc_uint32_t) - 1) / sizeof(isc_uint32_t);
9319 	for (i = 0; i < n; i++)
9320 		isc_random_get(&rnd.rnd32[i]);
9321 
9322 	memmove(salt, rnd.rnd, saltlen);
9323 
9324 	r.base = rnd.rnd;
9325 	r.length = (unsigned int) saltlen;
9326 
9327 	isc_buffer_init(&buf, text, sizeof(text));
9328 	result = isc_hex_totext(&r, 2, "", &buf);
9329 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9330 	text[saltlen * 2] = 0;
9331 
9332 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
9333 		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
9334 		      "generated salt: %s", text);
9335 
9336 	return (ISC_R_SUCCESS);
9337 }
9338 
9339 isc_result_t
9340 ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
9341 	isc_result_t result = ISC_R_SUCCESS;
9342 	dns_zone_t *zone = NULL;
9343 	dns_name_t *origin;
9344 	dns_db_t *db = NULL;
9345 	dns_dbnode_t *node = NULL;
9346 	dns_dbversion_t *version = NULL;
9347 	dns_rdatatype_t privatetype;
9348 	dns_rdataset_t privset;
9349 	isc_boolean_t first = ISC_TRUE;
9350 	isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE;
9351 	isc_boolean_t chain = ISC_FALSE;
9352 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
9353 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
9354 	unsigned char salt[255];
9355 	const char *ptr;
9356 	size_t n;
9357 
9358 	dns_rdataset_init(&privset);
9359 
9360 	/* Skip the command name. */
9361 	ptr = next_token(&args, " \t");
9362 	if (ptr == NULL)
9363 		return (ISC_R_UNEXPECTEDEND);
9364 
9365 	/* Find out what we are to do. */
9366 	ptr = next_token(&args, " \t");
9367 	if (ptr == NULL)
9368 		return (ISC_R_UNEXPECTEDEND);
9369 
9370 	if (strcasecmp(ptr, "-list") == 0)
9371 		list = ISC_TRUE;
9372 	else if ((strcasecmp(ptr, "-clear") == 0)  ||
9373 		 (strcasecmp(ptr, "-clean") == 0)) {
9374 		clear = ISC_TRUE;
9375 		ptr = next_token(&args, " \t");
9376 		if (ptr == NULL)
9377 			return (ISC_R_UNEXPECTEDEND);
9378 		strlcpy(keystr, ptr, sizeof(keystr));
9379 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
9380 		const char *hashstr, *flagstr, *iterstr;
9381 		char nbuf[512];
9382 
9383 		chain = ISC_TRUE;
9384 		hashstr = next_token(&args, " \t");
9385 		if (hashstr == NULL)
9386 			return (ISC_R_UNEXPECTEDEND);
9387 
9388 		if (strcasecmp(hashstr, "none") == 0)
9389 			hash = 0;
9390 		else {
9391 			flagstr = next_token(&args, " \t");
9392 			iterstr = next_token(&args, " \t");
9393 			if (flagstr == NULL || iterstr == NULL)
9394 				return (ISC_R_UNEXPECTEDEND);
9395 
9396 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
9397 				     hashstr, flagstr, iterstr);
9398 			if (n == sizeof(nbuf))
9399 				return (ISC_R_NOSPACE);
9400 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
9401 			if (n != 3U)
9402 				return (ISC_R_BADNUMBER);
9403 
9404 			if (hash > 0xffU || flags > 0xffU)
9405 				return (ISC_R_RANGE);
9406 
9407 			ptr = next_token(&args, " \t");
9408 			if (ptr == NULL) {
9409 				return (ISC_R_UNEXPECTEDEND);
9410 			} else if (strcasecmp(ptr, "auto") == 0) {
9411 				/* Auto-generate a random salt.
9412 				 * XXXMUKS: This currently uses the
9413 				 * minimum recommended length by RFC
9414 				 * 5155 (64 bits). It should be made
9415 				 * configurable.
9416 				 */
9417 				saltlen = 8;
9418 				CHECK(generate_salt(salt, saltlen));
9419 			} else if (strcmp(ptr, "-") != 0) {
9420 				isc_buffer_t buf;
9421 
9422 				isc_buffer_init(&buf, salt, sizeof(salt));
9423 				CHECK(isc_hex_decodestring(ptr, &buf));
9424 				saltlen = isc_buffer_usedlength(&buf);
9425 			}
9426 		}
9427 	} else
9428 		CHECK(DNS_R_SYNTAX);
9429 
9430 	CHECK(zone_from_args(server, args, NULL, &zone, NULL,
9431 			     text, ISC_FALSE));
9432 	if (zone == NULL)
9433 		CHECK(ISC_R_UNEXPECTEDEND);
9434 
9435 	if (clear) {
9436 		CHECK(dns_zone_keydone(zone, keystr));
9437 		putstr(text, "request queued");
9438 		putnull(text);
9439 	} else if (chain) {
9440 		CHECK(dns_zone_setnsec3param(zone, (isc_uint8_t)hash,
9441 					     (isc_uint8_t)flags, iter,
9442 					     (isc_uint8_t)saltlen, salt,
9443 					     ISC_TRUE));
9444 		putstr(text, "request queued");
9445 		putnull(text);
9446 	} else if (list) {
9447 		privatetype = dns_zone_getprivatetype(zone);
9448 		origin = dns_zone_getorigin(zone);
9449 		CHECK(dns_zone_getdb(zone, &db));
9450 		CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node));
9451 		dns_db_currentversion(db, &version);
9452 
9453 		result = dns_db_findrdataset(db, node, version, privatetype,
9454 					     dns_rdatatype_none, 0,
9455 					     &privset, NULL);
9456 		if (result == ISC_R_NOTFOUND) {
9457 			putstr(text, "No signing records found");
9458 			putnull(text);
9459 			result = ISC_R_SUCCESS;
9460 			goto cleanup;
9461 		}
9462 
9463 		for (result = dns_rdataset_first(&privset);
9464 		     result == ISC_R_SUCCESS;
9465 		     result = dns_rdataset_next(&privset))
9466 		{
9467 			dns_rdata_t priv = DNS_RDATA_INIT;
9468 			char output[BUFSIZ];
9469 			isc_buffer_t buf;
9470 
9471 			dns_rdataset_current(&privset, &priv);
9472 
9473 			isc_buffer_init(&buf, output, sizeof(output));
9474 			CHECK(dns_private_totext(&priv, &buf));
9475 
9476 			if (!first)
9477 				putstr(text, "\n");
9478 			first = ISC_FALSE;
9479 
9480 			n = snprintf((char *)isc_buffer_used(text),
9481 				     isc_buffer_availablelength(text),
9482 				     "%s", output);
9483 			if (n >= isc_buffer_availablelength(text))
9484 				CHECK(ISC_R_NOSPACE);
9485 
9486 			isc_buffer_add(text, (unsigned int)n);
9487 		}
9488 		if (!first)
9489 			putnull(text);
9490 
9491 		if (result == ISC_R_NOMORE)
9492 			result = ISC_R_SUCCESS;
9493 	}
9494 
9495  cleanup:
9496 	if (dns_rdataset_isassociated(&privset))
9497 		dns_rdataset_disassociate(&privset);
9498 	if (node != NULL)
9499 		dns_db_detachnode(db, &node);
9500 	if (version != NULL)
9501 		dns_db_closeversion(db, &version, ISC_FALSE);
9502 	if (db != NULL)
9503 		dns_db_detach(&db);
9504 	if (zone != NULL)
9505 		dns_zone_detach(&zone);
9506 
9507 	return (result);
9508 }
9509 
9510 static isc_result_t
9511 putstr(isc_buffer_t *b, const char *str) {
9512 	unsigned int l = strlen(str);
9513 
9514 	/*
9515 	 * Use >= to leave space for NUL termination.
9516 	 */
9517 	if (l >= isc_buffer_availablelength(b))
9518 		return (ISC_R_NOSPACE);
9519 
9520 	isc_buffer_putmem(b, (const unsigned char *)str, l);
9521 	return (ISC_R_SUCCESS);
9522 }
9523 
9524 static isc_result_t
9525 putnull(isc_buffer_t *b) {
9526 	if (isc_buffer_availablelength(b) == 0)
9527 		return (ISC_R_NOSPACE);
9528 
9529 	isc_buffer_putuint8(b, 0);
9530 	return (ISC_R_SUCCESS);
9531 }
9532 
9533 isc_result_t
9534 ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t *text) {
9535 	isc_result_t result = ISC_R_SUCCESS;
9536 	dns_zone_t *zone = NULL, *raw = NULL;
9537 	const char *type, *file, *zonename = NULL;
9538 	isc_uint32_t serial, signed_serial, nodes;
9539 	char serbuf[16], sserbuf[16], nodebuf[16], resignbuf[512];
9540 	char lbuf[80], xbuf[80], rbuf[80], kbuf[80], rtbuf[80];
9541 	isc_time_t loadtime, expiretime, refreshtime;
9542 	isc_time_t refreshkeytime, resigntime;
9543 	dns_zonetype_t zonetype;
9544 	isc_boolean_t dynamic = ISC_FALSE, frozen = ISC_FALSE;
9545 	isc_boolean_t hasraw = ISC_FALSE;
9546 	isc_boolean_t secure, maintain, allow;
9547 	dns_db_t *db = NULL, *rawdb = NULL;
9548 	char **incfiles = NULL;
9549 	int nfiles = 0;
9550 
9551 	isc_time_settoepoch(&loadtime);
9552 	isc_time_settoepoch(&refreshtime);
9553 	isc_time_settoepoch(&expiretime);
9554 	isc_time_settoepoch(&refreshkeytime);
9555 	isc_time_settoepoch(&resigntime);
9556 
9557 	CHECK(zone_from_args(server, args, NULL, &zone, &zonename,
9558 			     text, ISC_TRUE));
9559 	if (zone == NULL) {
9560 		result = ISC_R_UNEXPECTEDEND;
9561 		goto cleanup;
9562 	}
9563 
9564 	zonetype = dns_zone_gettype(zone);
9565 	switch (zonetype) {
9566 	case dns_zone_master:
9567 		type = "master";
9568 		break;
9569 	case dns_zone_slave:
9570 		type = "slave";
9571 		break;
9572 	case dns_zone_stub:
9573 		type = "stub";
9574 		break;
9575 	case dns_zone_staticstub:
9576 		type = "staticstub";
9577 		break;
9578 	case dns_zone_redirect:
9579 		type = "redirect";
9580 		break;
9581 	case dns_zone_key:
9582 		type = "key";
9583 		break;
9584 	case dns_zone_dlz:
9585 		type = "dlz";
9586 		break;
9587 	default:
9588 		type = "unknown";
9589 	}
9590 
9591 	/* Inline signing? */
9592 	CHECK(dns_zone_getdb(zone, &db));
9593 	dns_zone_getraw(zone, &raw);
9594 	hasraw = ISC_TF(raw != NULL);
9595 	if (hasraw)
9596 		CHECK(dns_zone_getdb(raw, &rawdb));
9597 
9598 	/* Serial number */
9599 	serial = dns_zone_getserial(hasraw ? raw : zone);
9600 	snprintf(serbuf, sizeof(serbuf), "%d", serial);
9601 	if (hasraw) {
9602 		signed_serial = dns_zone_getserial(zone);
9603 		snprintf(sserbuf, sizeof(sserbuf), "%d", signed_serial);
9604 	}
9605 
9606 	/* Database node count */
9607 	nodes = dns_db_nodecount(hasraw ? rawdb : db);
9608 	snprintf(nodebuf, sizeof(nodebuf), "%d", nodes);
9609 
9610 	/* Security */
9611 	secure = dns_db_issecure(db);
9612 	allow = ISC_TF((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
9613 	maintain = ISC_TF((dns_zone_getkeyopts(zone) &
9614 			   DNS_ZONEKEY_MAINTAIN) != 0);
9615 
9616 	/* Master files */
9617 	file = dns_zone_getfile(hasraw ? raw : zone);
9618 	nfiles = dns_zone_getincludes(hasraw ? raw : zone, &incfiles);
9619 
9620 	/* Load time */
9621 	dns_zone_getloadtime(zone, &loadtime);
9622 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
9623 
9624 	/* Refresh/expire times */
9625 	if (zonetype == dns_zone_slave ||
9626 	    zonetype == dns_zone_stub ||
9627 	    zonetype == dns_zone_redirect)
9628 	{
9629 		dns_zone_getexpiretime(zone, &expiretime);
9630 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
9631 		dns_zone_getrefreshtime(zone, &refreshtime);
9632 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
9633 	}
9634 
9635 	/* Key refresh time */
9636 	if (zonetype == dns_zone_master ||
9637 	    (zonetype == dns_zone_slave && hasraw))
9638 	{
9639 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
9640 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
9641 					     sizeof(kbuf));
9642 	}
9643 
9644 	/* Dynamic? */
9645 	if (zonetype == dns_zone_master) {
9646 		dynamic = dns_zone_isdynamic(hasraw ? raw : zone, ISC_TRUE);
9647 		frozen = dynamic && !dns_zone_isdynamic(hasraw ? raw : zone,
9648 							ISC_FALSE);
9649 	}
9650 
9651 	/* Next resign event */
9652 	if (secure && (zonetype == dns_zone_master ||
9653 	     (zonetype == dns_zone_slave && hasraw)) &&
9654 	    ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
9655 	{
9656 		dns_name_t *name;
9657 		dns_fixedname_t fixed;
9658 		dns_rdataset_t next;
9659 
9660 		dns_rdataset_init(&next);
9661 		dns_fixedname_init(&fixed);
9662 		name = dns_fixedname_name(&fixed);
9663 
9664 		result = dns_db_getsigningtime(db, &next, name);
9665 		if (result == ISC_R_SUCCESS) {
9666 			isc_stdtime_t timenow;
9667 			char namebuf[DNS_NAME_FORMATSIZE];
9668 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
9669 
9670 			isc_stdtime_get(&timenow);
9671 			dns_name_format(name, namebuf, sizeof(namebuf));
9672 			dns_rdatatype_format(next.covers,
9673 					     typebuf, sizeof(typebuf));
9674 			snprintf(resignbuf, sizeof(resignbuf),
9675 				     "%s/%s", namebuf, typebuf);
9676 			isc_time_set(&resigntime, next.resign -
9677 				dns_zone_getsigresigninginterval(zone), 0);
9678 			isc_time_formathttptimestamp(&resigntime, rtbuf,
9679 						     sizeof(rtbuf));
9680 			dns_rdataset_disassociate(&next);
9681 		}
9682 	}
9683 
9684 	/* Create text */
9685 	CHECK(putstr(text, "name: "));
9686 	CHECK(putstr(text, zonename));
9687 
9688 	CHECK(putstr(text, "\ntype: "));
9689 	CHECK(putstr(text, type));
9690 
9691 	if (file != NULL) {
9692 		int i;
9693 		CHECK(putstr(text, "\nfiles: "));
9694 		CHECK(putstr(text, file));
9695 		for (i = 0; i < nfiles; i++) {
9696 			CHECK(putstr(text, ", "));
9697 			if (incfiles[i] != NULL)
9698 				CHECK(putstr(text, incfiles[i]));
9699 		}
9700 	}
9701 
9702 	CHECK(putstr(text, "\nserial: "));
9703 	CHECK(putstr(text, serbuf));
9704 	if (hasraw) {
9705 		CHECK(putstr(text, "\nsigned serial: "));
9706 		CHECK(putstr(text, sserbuf));
9707 	}
9708 
9709 	CHECK(putstr(text, "\nnodes: "));
9710 	CHECK(putstr(text, nodebuf));
9711 
9712 	if (! isc_time_isepoch(&loadtime)) {
9713 		CHECK(putstr(text, "\nlast loaded: "));
9714 		CHECK(putstr(text, lbuf));
9715 	}
9716 
9717 	if (! isc_time_isepoch(&refreshtime)) {
9718 		CHECK(putstr(text, "\nnext refresh: "));
9719 		CHECK(putstr(text, rbuf));
9720 	}
9721 
9722 	if (! isc_time_isepoch(&expiretime)) {
9723 		CHECK(putstr(text, "\nexpires: "));
9724 		CHECK(putstr(text, xbuf));
9725 	}
9726 
9727 	if (secure) {
9728 		CHECK(putstr(text, "\nsecure: yes"));
9729 		if (hasraw)
9730 			CHECK(putstr(text, "\ninline signing: yes"));
9731 		else
9732 			CHECK(putstr(text, "\ninline signing: no"));
9733 	} else
9734 		CHECK(putstr(text, "\nsecure: no"));
9735 
9736 	if (maintain) {
9737 		CHECK(putstr(text, "\nkey maintenance: automatic"));
9738 		if (! isc_time_isepoch(&refreshkeytime)) {
9739 			CHECK(putstr(text, "\nnext key event: "));
9740 			CHECK(putstr(text, kbuf));
9741 		}
9742 	} else if (allow)
9743 		CHECK(putstr(text, "\nkey maintenance: on command"));
9744 	else if (secure || hasraw)
9745 		CHECK(putstr(text, "\nkey maintenance: none"));
9746 
9747 	if (!isc_time_isepoch(&resigntime)) {
9748 		CHECK(putstr(text, "\nnext resign node: "));
9749 		CHECK(putstr(text, resignbuf));
9750 		CHECK(putstr(text, "\nnext resign time: "));
9751 		CHECK(putstr(text, rtbuf));
9752 	}
9753 
9754 	if (dynamic) {
9755 		CHECK(putstr(text, "\ndynamic: yes"));
9756 		if (frozen)
9757 			CHECK(putstr(text, "\nfrozen: yes"));
9758 		else
9759 			CHECK(putstr(text, "\nfrozen: no"));
9760 	} else
9761 		CHECK(putstr(text, "\ndynamic: no"));
9762 
9763  cleanup:
9764 	/* Indicate truncated output if possible. */
9765 	if (result == ISC_R_NOSPACE)
9766 		(void) putstr(text, "\n...");
9767 	if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE))
9768 		putnull(text);
9769 
9770 	if (db != NULL)
9771 		dns_db_detach(&db);
9772 	if (rawdb != NULL)
9773 		dns_db_detach(&rawdb);
9774 	if (incfiles != NULL) {
9775 		int i;
9776 		isc_mem_t *mctx = dns_zone_getmctx(hasraw ? raw : zone);
9777 
9778 		for (i = 0; i < nfiles; i++)
9779 			if (incfiles[i] != NULL)
9780 				isc_mem_free(mctx, incfiles[i]);
9781 		isc_mem_free(mctx, incfiles);
9782 	}
9783 	if (raw != NULL)
9784 		dns_zone_detach(&raw);
9785 	if (zone != NULL)
9786 		dns_zone_detach(&zone);
9787 	return (result);
9788 }
9789