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