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