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