server.c revision 225361
1/*
2 * Copyright (C) 2004-2011  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.12 2011-08-02 04:58:45 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] = { "_builtin", "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		dlvobj = cfg_listelt_value(cfg_list_first(obj));
2600		if (!strcmp(cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain")),
2601			    "auto") &&
2602		    cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
2603			auto_dlv = ISC_TRUE;
2604			obj = NULL;
2605			result = cfg_map_get(ns_g_defaults,
2606					     "dnssec-lookaside", &obj);
2607		}
2608	}
2609
2610	if (result == ISC_R_SUCCESS) {
2611		for (element = cfg_list_first(obj);
2612		     element != NULL;
2613		     element = cfg_list_next(element))
2614		{
2615			const char *str;
2616			isc_buffer_t b;
2617			dns_name_t *dlv;
2618
2619			obj = cfg_listelt_value(element);
2620			str = cfg_obj_asstring(cfg_tuple_get(obj,
2621							     "trust-anchor"));
2622			isc_buffer_init(&b, str, strlen(str));
2623			isc_buffer_add(&b, strlen(str));
2624			dlv = dns_fixedname_name(&view->dlv_fixed);
2625			CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
2626						DNS_NAME_DOWNCASE, NULL));
2627			view->dlv = dns_fixedname_name(&view->dlv_fixed);
2628		}
2629	} else
2630		view->dlv = NULL;
2631
2632	/*
2633	 * For now, there is only one kind of trusted keys, the
2634	 * "security roots".
2635	 */
2636	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
2637					auto_dlv, auto_root, mctx));
2638	dns_resolver_resetmustbesecure(view->resolver);
2639	obj = NULL;
2640	result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
2641	if (result == ISC_R_SUCCESS)
2642		CHECK(mustbesecure(obj, view->resolver));
2643
2644	obj = NULL;
2645	result = ns_config_get(maps, "preferred-glue", &obj);
2646	if (result == ISC_R_SUCCESS) {
2647		str = cfg_obj_asstring(obj);
2648		if (strcasecmp(str, "a") == 0)
2649			view->preferred_glue = dns_rdatatype_a;
2650		else if (strcasecmp(str, "aaaa") == 0)
2651			view->preferred_glue = dns_rdatatype_aaaa;
2652		else
2653			view->preferred_glue = 0;
2654	} else
2655		view->preferred_glue = 0;
2656
2657	obj = NULL;
2658	result = ns_config_get(maps, "root-delegation-only", &obj);
2659	if (result == ISC_R_SUCCESS) {
2660		dns_view_setrootdelonly(view, ISC_TRUE);
2661		if (!cfg_obj_isvoid(obj)) {
2662			dns_fixedname_t fixed;
2663			dns_name_t *name;
2664			isc_buffer_t b;
2665			const char *str;
2666			const cfg_obj_t *exclude;
2667
2668			dns_fixedname_init(&fixed);
2669			name = dns_fixedname_name(&fixed);
2670			for (element = cfg_list_first(obj);
2671			     element != NULL;
2672			     element = cfg_list_next(element)) {
2673				exclude = cfg_listelt_value(element);
2674				str = cfg_obj_asstring(exclude);
2675				isc_buffer_init(&b, str, strlen(str));
2676				isc_buffer_add(&b, strlen(str));
2677				CHECK(dns_name_fromtext(name, &b, dns_rootname,
2678							0, NULL));
2679				CHECK(dns_view_excludedelegationonly(view,
2680								     name));
2681			}
2682		}
2683	} else
2684		dns_view_setrootdelonly(view, ISC_FALSE);
2685
2686	/*
2687	 * Setup automatic empty zones.  If recursion is off then
2688	 * they are disabled by default.
2689	 */
2690	obj = NULL;
2691	(void)ns_config_get(maps, "empty-zones-enable", &obj);
2692	(void)ns_config_get(maps, "disable-empty-zone", &disablelist);
2693	if (obj == NULL && disablelist == NULL &&
2694	    view->rdclass == dns_rdataclass_in) {
2695		rfc1918 = ISC_FALSE;
2696		empty_zones_enable = view->recursion;
2697	} else if (view->rdclass == dns_rdataclass_in) {
2698		rfc1918 = ISC_TRUE;
2699		if (obj != NULL)
2700			empty_zones_enable = cfg_obj_asboolean(obj);
2701		else
2702			empty_zones_enable = view->recursion;
2703	} else {
2704		rfc1918 = ISC_FALSE;
2705		empty_zones_enable = ISC_FALSE;
2706	}
2707	if (empty_zones_enable) {
2708		const char *empty;
2709		int empty_zone = 0;
2710		dns_fixedname_t fixed;
2711		dns_name_t *name;
2712		isc_buffer_t buffer;
2713		const char *str;
2714		char server[DNS_NAME_FORMATSIZE + 1];
2715		char contact[DNS_NAME_FORMATSIZE + 1];
2716		isc_boolean_t logit;
2717		const char *empty_dbtype[4] =
2718				    { "_builtin", "empty", NULL, NULL };
2719		int empty_dbtypec = 4;
2720		isc_boolean_t zonestats_on;
2721
2722		dns_fixedname_init(&fixed);
2723		name = dns_fixedname_name(&fixed);
2724
2725		obj = NULL;
2726		result = ns_config_get(maps, "empty-server", &obj);
2727		if (result == ISC_R_SUCCESS) {
2728			str = cfg_obj_asstring(obj);
2729			isc_buffer_init(&buffer, str, strlen(str));
2730			isc_buffer_add(&buffer, strlen(str));
2731			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2732						NULL));
2733			isc_buffer_init(&buffer, server, sizeof(server) - 1);
2734			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
2735			server[isc_buffer_usedlength(&buffer)] = 0;
2736			empty_dbtype[2] = server;
2737		} else
2738			empty_dbtype[2] = "@";
2739
2740		obj = NULL;
2741		result = ns_config_get(maps, "empty-contact", &obj);
2742		if (result == ISC_R_SUCCESS) {
2743			str = cfg_obj_asstring(obj);
2744			isc_buffer_init(&buffer, str, strlen(str));
2745			isc_buffer_add(&buffer, strlen(str));
2746			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2747						NULL));
2748			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
2749			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
2750			contact[isc_buffer_usedlength(&buffer)] = 0;
2751			empty_dbtype[3] = contact;
2752		} else
2753			empty_dbtype[3] = ".";
2754
2755		obj = NULL;
2756		result = ns_config_get(maps, "zone-statistics", &obj);
2757		INSIST(result == ISC_R_SUCCESS);
2758		zonestats_on = cfg_obj_asboolean(obj);
2759
2760		logit = ISC_TRUE;
2761		for (empty = empty_zones[empty_zone].zone;
2762		     empty != NULL;
2763		     empty = empty_zones[++empty_zone].zone)
2764		{
2765			dns_forwarders_t *forwarders = NULL;
2766			dns_view_t *pview = NULL;
2767
2768			isc_buffer_init(&buffer, empty, strlen(empty));
2769			isc_buffer_add(&buffer, strlen(empty));
2770			/*
2771			 * Look for zone on drop list.
2772			 */
2773			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2774						NULL));
2775			if (disablelist != NULL &&
2776			    on_disable_list(disablelist, name))
2777				continue;
2778
2779			/*
2780			 * This zone already exists.
2781			 */
2782			(void)dns_view_findzone(view, name, &zone);
2783			if (zone != NULL) {
2784				CHECK(setquerystats(zone, mctx, zonestats_on));
2785				dns_zone_detach(&zone);
2786				continue;
2787			}
2788
2789			/*
2790			 * If we would forward this name don't add a
2791			 * empty zone for it.
2792			 */
2793			result = dns_fwdtable_find(view->fwdtable, name,
2794						   &forwarders);
2795			if (result == ISC_R_SUCCESS &&
2796			    forwarders->fwdpolicy == dns_fwdpolicy_only)
2797				continue;
2798
2799			if (!rfc1918 && empty_zones[empty_zone].rfc1918) {
2800				if (logit) {
2801					isc_log_write(ns_g_lctx,
2802						      NS_LOGCATEGORY_GENERAL,
2803						      NS_LOGMODULE_SERVER,
2804						      ISC_LOG_WARNING,
2805						      "Warning%s%s: "
2806						      "'empty-zones-enable/"
2807						      "disable-empty-zone' "
2808						      "not set: disabling "
2809						      "RFC 1918 empty zones",
2810						      sep, viewname);
2811					logit = ISC_FALSE;
2812				}
2813				continue;
2814			}
2815
2816			/*
2817			 * See if we can re-use a existing zone.
2818			 */
2819			result = dns_viewlist_find(&ns_g_server->viewlist,
2820						   view->name, view->rdclass,
2821						   &pview);
2822			if (result != ISC_R_NOTFOUND &&
2823			    result != ISC_R_SUCCESS)
2824				goto cleanup;
2825
2826			if (pview != NULL) {
2827				(void)dns_view_findzone(pview, name, &zone);
2828				dns_view_detach(&pview);
2829				if (zone != NULL)
2830					check_dbtype(&zone, empty_dbtypec,
2831						     empty_dbtype, mctx);
2832				if (zone != NULL) {
2833					dns_zone_setview(zone, view);
2834					CHECK(dns_view_addzone(view, zone));
2835					CHECK(setquerystats(zone, mctx,
2836							    zonestats_on));
2837					dns_zone_detach(&zone);
2838					continue;
2839				}
2840			}
2841
2842			CHECK(dns_zone_create(&zone, mctx));
2843			CHECK(dns_zone_setorigin(zone, name));
2844			dns_zone_setview(zone, view);
2845			CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
2846			dns_zone_setclass(zone, view->rdclass);
2847			dns_zone_settype(zone, dns_zone_master);
2848			dns_zone_setstats(zone, ns_g_server->zonestats);
2849			CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
2850						 empty_dbtype));
2851			if (view->queryacl != NULL)
2852				dns_zone_setqueryacl(zone, view->queryacl);
2853			if (view->queryonacl != NULL)
2854				dns_zone_setqueryonacl(zone, view->queryonacl);
2855			dns_zone_setdialup(zone, dns_dialuptype_no);
2856			dns_zone_setnotifytype(zone, dns_notifytype_no);
2857			dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS,
2858					   ISC_TRUE);
2859			CHECK(setquerystats(zone, mctx, zonestats_on));
2860			CHECK(dns_view_addzone(view, zone));
2861			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2862				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2863				      "automatic empty zone%s%s: %s",
2864				      sep, viewname,  empty);
2865			dns_zone_detach(&zone);
2866		}
2867	}
2868
2869	/*
2870	 * Make the list of response policy zone names for views that
2871	 * are used for real lookups and so care about hints.
2872	 */
2873	zonelist = NULL;
2874	if (view->rdclass == dns_rdataclass_in && need_hints) {
2875		obj = NULL;
2876		result = ns_config_get(maps, "response-policy", &obj);
2877		if (result == ISC_R_SUCCESS)
2878			cfg_map_get(obj, "zone", &zonelist);
2879	}
2880
2881	if (zonelist != NULL) {
2882		for (element = cfg_list_first(zonelist);
2883		     element != NULL;
2884		     element = cfg_list_next(element)) {
2885			result = configure_rpz(view, element);
2886			if (result != ISC_R_SUCCESS)
2887				goto cleanup;
2888			dns_rpz_set_need(ISC_TRUE);
2889		}
2890	}
2891
2892	result = ISC_R_SUCCESS;
2893
2894 cleanup:
2895	if (clients != NULL)
2896		dns_acl_detach(&clients);
2897	if (mapped != NULL)
2898		dns_acl_detach(&mapped);
2899	if (excluded != NULL)
2900		dns_acl_detach(&excluded);
2901	if (ring != NULL)
2902		dns_tsigkeyring_detach(&ring);
2903	if (zone != NULL)
2904		dns_zone_detach(&zone);
2905	if (dispatch4 != NULL)
2906		dns_dispatch_detach(&dispatch4);
2907	if (dispatch6 != NULL)
2908		dns_dispatch_detach(&dispatch6);
2909	if (resstats != NULL)
2910		isc_stats_detach(&resstats);
2911	if (resquerystats != NULL)
2912		dns_stats_detach(&resquerystats);
2913	if (order != NULL)
2914		dns_order_detach(&order);
2915	if (cmctx != NULL)
2916		isc_mem_detach(&cmctx);
2917	if (hmctx != NULL)
2918		isc_mem_detach(&hmctx);
2919
2920	if (cache != NULL)
2921		dns_cache_detach(&cache);
2922
2923	return (result);
2924}
2925
2926static isc_result_t
2927configure_hints(dns_view_t *view, const char *filename) {
2928	isc_result_t result;
2929	dns_db_t *db;
2930
2931	db = NULL;
2932	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
2933	if (result == ISC_R_SUCCESS) {
2934		dns_view_sethints(view, db);
2935		dns_db_detach(&db);
2936	}
2937
2938	return (result);
2939}
2940
2941static isc_result_t
2942configure_alternates(const cfg_obj_t *config, dns_view_t *view,
2943		     const cfg_obj_t *alternates)
2944{
2945	const cfg_obj_t *portobj;
2946	const cfg_obj_t *addresses;
2947	const cfg_listelt_t *element;
2948	isc_result_t result = ISC_R_SUCCESS;
2949	in_port_t port;
2950
2951	/*
2952	 * Determine which port to send requests to.
2953	 */
2954	if (ns_g_lwresdonly && ns_g_port != 0)
2955		port = ns_g_port;
2956	else
2957		CHECKM(ns_config_getport(config, &port), "port");
2958
2959	if (alternates != NULL) {
2960		portobj = cfg_tuple_get(alternates, "port");
2961		if (cfg_obj_isuint32(portobj)) {
2962			isc_uint32_t val = cfg_obj_asuint32(portobj);
2963			if (val > ISC_UINT16_MAX) {
2964				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
2965					    "port '%u' out of range", val);
2966				return (ISC_R_RANGE);
2967			}
2968			port = (in_port_t) val;
2969		}
2970	}
2971
2972	addresses = NULL;
2973	if (alternates != NULL)
2974		addresses = cfg_tuple_get(alternates, "addresses");
2975
2976	for (element = cfg_list_first(addresses);
2977	     element != NULL;
2978	     element = cfg_list_next(element))
2979	{
2980		const cfg_obj_t *alternate = cfg_listelt_value(element);
2981		isc_sockaddr_t sa;
2982
2983		if (!cfg_obj_issockaddr(alternate)) {
2984			dns_fixedname_t fixed;
2985			dns_name_t *name;
2986			const char *str = cfg_obj_asstring(cfg_tuple_get(
2987							   alternate, "name"));
2988			isc_buffer_t buffer;
2989			in_port_t myport = port;
2990
2991			isc_buffer_init(&buffer, str, strlen(str));
2992			isc_buffer_add(&buffer, strlen(str));
2993			dns_fixedname_init(&fixed);
2994			name = dns_fixedname_name(&fixed);
2995			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2996						NULL));
2997
2998			portobj = cfg_tuple_get(alternate, "port");
2999			if (cfg_obj_isuint32(portobj)) {
3000				isc_uint32_t val = cfg_obj_asuint32(portobj);
3001				if (val > ISC_UINT16_MAX) {
3002					cfg_obj_log(portobj, ns_g_lctx,
3003						    ISC_LOG_ERROR,
3004						    "port '%u' out of range",
3005						     val);
3006					return (ISC_R_RANGE);
3007				}
3008				myport = (in_port_t) val;
3009			}
3010			CHECK(dns_resolver_addalternate(view->resolver, NULL,
3011							name, myport));
3012			continue;
3013		}
3014
3015		sa = *cfg_obj_assockaddr(alternate);
3016		if (isc_sockaddr_getport(&sa) == 0)
3017			isc_sockaddr_setport(&sa, port);
3018		CHECK(dns_resolver_addalternate(view->resolver, &sa,
3019						NULL, 0));
3020	}
3021
3022 cleanup:
3023	return (result);
3024}
3025
3026static isc_result_t
3027configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
3028		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
3029{
3030	const cfg_obj_t *portobj;
3031	const cfg_obj_t *faddresses;
3032	const cfg_listelt_t *element;
3033	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
3034	isc_sockaddrlist_t addresses;
3035	isc_sockaddr_t *sa;
3036	isc_result_t result;
3037	in_port_t port;
3038
3039	ISC_LIST_INIT(addresses);
3040
3041	/*
3042	 * Determine which port to send forwarded requests to.
3043	 */
3044	if (ns_g_lwresdonly && ns_g_port != 0)
3045		port = ns_g_port;
3046	else
3047		CHECKM(ns_config_getport(config, &port), "port");
3048
3049	if (forwarders != NULL) {
3050		portobj = cfg_tuple_get(forwarders, "port");
3051		if (cfg_obj_isuint32(portobj)) {
3052			isc_uint32_t val = cfg_obj_asuint32(portobj);
3053			if (val > ISC_UINT16_MAX) {
3054				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3055					    "port '%u' out of range", val);
3056				return (ISC_R_RANGE);
3057			}
3058			port = (in_port_t) val;
3059		}
3060	}
3061
3062	faddresses = NULL;
3063	if (forwarders != NULL)
3064		faddresses = cfg_tuple_get(forwarders, "addresses");
3065
3066	for (element = cfg_list_first(faddresses);
3067	     element != NULL;
3068	     element = cfg_list_next(element))
3069	{
3070		const cfg_obj_t *forwarder = cfg_listelt_value(element);
3071		sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
3072		if (sa == NULL) {
3073			result = ISC_R_NOMEMORY;
3074			goto cleanup;
3075		}
3076		*sa = *cfg_obj_assockaddr(forwarder);
3077		if (isc_sockaddr_getport(sa) == 0)
3078			isc_sockaddr_setport(sa, port);
3079		ISC_LINK_INIT(sa, link);
3080		ISC_LIST_APPEND(addresses, sa, link);
3081	}
3082
3083	if (ISC_LIST_EMPTY(addresses)) {
3084		if (forwardtype != NULL)
3085			cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3086				    "no forwarders seen; disabling "
3087				    "forwarding");
3088		fwdpolicy = dns_fwdpolicy_none;
3089	} else {
3090		if (forwardtype == NULL)
3091			fwdpolicy = dns_fwdpolicy_first;
3092		else {
3093			const char *forwardstr = cfg_obj_asstring(forwardtype);
3094			if (strcasecmp(forwardstr, "first") == 0)
3095				fwdpolicy = dns_fwdpolicy_first;
3096			else if (strcasecmp(forwardstr, "only") == 0)
3097				fwdpolicy = dns_fwdpolicy_only;
3098			else
3099				INSIST(0);
3100		}
3101	}
3102
3103	result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
3104				  fwdpolicy);
3105	if (result != ISC_R_SUCCESS) {
3106		char namebuf[DNS_NAME_FORMATSIZE];
3107		dns_name_format(origin, namebuf, sizeof(namebuf));
3108		cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3109			    "could not set up forwarding for domain '%s': %s",
3110			    namebuf, isc_result_totext(result));
3111		goto cleanup;
3112	}
3113
3114	result = ISC_R_SUCCESS;
3115
3116 cleanup:
3117
3118	while (!ISC_LIST_EMPTY(addresses)) {
3119		sa = ISC_LIST_HEAD(addresses);
3120		ISC_LIST_UNLINK(addresses, sa, link);
3121		isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
3122	}
3123
3124	return (result);
3125}
3126
3127static isc_result_t
3128get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
3129	     dns_rdataclass_t *classp)
3130{
3131	isc_result_t result = ISC_R_SUCCESS;
3132	const char *viewname;
3133	dns_rdataclass_t viewclass;
3134
3135	REQUIRE(namep != NULL && *namep == NULL);
3136	REQUIRE(classp != NULL);
3137
3138	if (vconfig != NULL) {
3139		const cfg_obj_t *classobj = NULL;
3140
3141		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
3142		classobj = cfg_tuple_get(vconfig, "class");
3143		result = ns_config_getclass(classobj, dns_rdataclass_in,
3144					    &viewclass);
3145	} else {
3146		viewname = "_default";
3147		viewclass = dns_rdataclass_in;
3148	}
3149
3150	*namep = viewname;
3151	*classp = viewclass;
3152
3153	return (result);
3154}
3155
3156/*
3157 * Find a view based on its configuration info and attach to it.
3158 *
3159 * If 'vconfig' is NULL, attach to the default view.
3160 */
3161static isc_result_t
3162find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3163	  dns_view_t **viewp)
3164{
3165	isc_result_t result;
3166	const char *viewname = NULL;
3167	dns_rdataclass_t viewclass;
3168	dns_view_t *view = NULL;
3169
3170	result = get_viewinfo(vconfig, &viewname, &viewclass);
3171	if (result != ISC_R_SUCCESS)
3172		return (result);
3173
3174	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3175	if (result != ISC_R_SUCCESS)
3176		return (result);
3177
3178	*viewp = view;
3179	return (ISC_R_SUCCESS);
3180}
3181
3182/*
3183 * Create a new view and add it to the list.
3184 *
3185 * If 'vconfig' is NULL, create the default view.
3186 *
3187 * The view created is attached to '*viewp'.
3188 */
3189static isc_result_t
3190create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3191	    dns_view_t **viewp)
3192{
3193	isc_result_t result;
3194	const char *viewname = NULL;
3195	dns_rdataclass_t viewclass;
3196	dns_view_t *view = NULL;
3197
3198	result = get_viewinfo(vconfig, &viewname, &viewclass);
3199	if (result != ISC_R_SUCCESS)
3200		return (result);
3201
3202	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3203	if (result == ISC_R_SUCCESS)
3204		return (ISC_R_EXISTS);
3205	if (result != ISC_R_NOTFOUND)
3206		return (result);
3207	INSIST(view == NULL);
3208
3209	result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
3210	if (result != ISC_R_SUCCESS)
3211		return (result);
3212
3213	ISC_LIST_APPEND(*viewlist, view, link);
3214	dns_view_attach(view, viewp);
3215	return (ISC_R_SUCCESS);
3216}
3217
3218/*
3219 * Configure or reconfigure a zone.
3220 */
3221static isc_result_t
3222configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
3223	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
3224	       cfg_aclconfctx_t *aclconf, isc_boolean_t added)
3225{
3226	dns_view_t *pview = NULL;	/* Production view */
3227	dns_zone_t *zone = NULL;	/* New or reused zone */
3228	dns_zone_t *dupzone = NULL;
3229	const cfg_obj_t *options = NULL;
3230	const cfg_obj_t *zoptions = NULL;
3231	const cfg_obj_t *typeobj = NULL;
3232	const cfg_obj_t *forwarders = NULL;
3233	const cfg_obj_t *forwardtype = NULL;
3234	const cfg_obj_t *only = NULL;
3235	isc_result_t result;
3236	isc_result_t tresult;
3237	isc_buffer_t buffer;
3238	dns_fixedname_t fixorigin;
3239	dns_name_t *origin;
3240	const char *zname;
3241	dns_rdataclass_t zclass;
3242	const char *ztypestr;
3243
3244	options = NULL;
3245	(void)cfg_map_get(config, "options", &options);
3246
3247	zoptions = cfg_tuple_get(zconfig, "options");
3248
3249	/*
3250	 * Get the zone origin as a dns_name_t.
3251	 */
3252	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3253	isc_buffer_init(&buffer, zname, strlen(zname));
3254	isc_buffer_add(&buffer, strlen(zname));
3255	dns_fixedname_init(&fixorigin);
3256	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
3257				&buffer, dns_rootname, 0, NULL));
3258	origin = dns_fixedname_name(&fixorigin);
3259
3260	CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
3261				 view->rdclass, &zclass));
3262	if (zclass != view->rdclass) {
3263		const char *vname = NULL;
3264		if (vconfig != NULL)
3265			vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
3266							       "name"));
3267		else
3268			vname = "<default view>";
3269
3270		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3271			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3272			      "zone '%s': wrong class for view '%s'",
3273			      zname, vname);
3274		result = ISC_R_FAILURE;
3275		goto cleanup;
3276	}
3277
3278	(void)cfg_map_get(zoptions, "type", &typeobj);
3279	if (typeobj == NULL) {
3280		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3281			    "zone '%s' 'type' not specified", zname);
3282		return (ISC_R_FAILURE);
3283	}
3284	ztypestr = cfg_obj_asstring(typeobj);
3285
3286	/*
3287	 * "hints zones" aren't zones.	If we've got one,
3288	 * configure it and return.
3289	 */
3290	if (strcasecmp(ztypestr, "hint") == 0) {
3291		const cfg_obj_t *fileobj = NULL;
3292		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
3293			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3294				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3295				      "zone '%s': 'file' not specified",
3296				      zname);
3297			result = ISC_R_FAILURE;
3298			goto cleanup;
3299		}
3300		if (dns_name_equal(origin, dns_rootname)) {
3301			const char *hintsfile = cfg_obj_asstring(fileobj);
3302
3303			result = configure_hints(view, hintsfile);
3304			if (result != ISC_R_SUCCESS) {
3305				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3306					      NS_LOGMODULE_SERVER,
3307					      ISC_LOG_ERROR,
3308					      "could not configure root hints "
3309					      "from '%s': %s", hintsfile,
3310					      isc_result_totext(result));
3311				goto cleanup;
3312			}
3313			/*
3314			 * Hint zones may also refer to delegation only points.
3315			 */
3316			only = NULL;
3317			tresult = cfg_map_get(zoptions, "delegation-only",
3318					      &only);
3319			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
3320				CHECK(dns_view_adddelegationonly(view, origin));
3321		} else {
3322			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3323				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3324				      "ignoring non-root hint zone '%s'",
3325				      zname);
3326			result = ISC_R_SUCCESS;
3327		}
3328		/* Skip ordinary zone processing. */
3329		goto cleanup;
3330	}
3331
3332	/*
3333	 * "forward zones" aren't zones either.  Translate this syntax into
3334	 * the appropriate selective forwarding configuration and return.
3335	 */
3336	if (strcasecmp(ztypestr, "forward") == 0) {
3337		forwardtype = NULL;
3338		forwarders = NULL;
3339
3340		(void)cfg_map_get(zoptions, "forward", &forwardtype);
3341		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
3342		result = configure_forward(config, view, origin, forwarders,
3343					   forwardtype);
3344		goto cleanup;
3345	}
3346
3347	/*
3348	 * "delegation-only zones" aren't zones either.
3349	 */
3350	if (strcasecmp(ztypestr, "delegation-only") == 0) {
3351		result = dns_view_adddelegationonly(view, origin);
3352		goto cleanup;
3353	}
3354
3355	/*
3356	 * Check for duplicates in the new zone table.
3357	 */
3358	result = dns_view_findzone(view, origin, &dupzone);
3359	if (result == ISC_R_SUCCESS) {
3360		/*
3361		 * We already have this zone!
3362		 */
3363		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3364			    "zone '%s' already exists", zname);
3365		dns_zone_detach(&dupzone);
3366		result = ISC_R_EXISTS;
3367		goto cleanup;
3368	}
3369	INSIST(dupzone == NULL);
3370
3371	/*
3372	 * See if we can reuse an existing zone.  This is
3373	 * only possible if all of these are true:
3374	 *   - The zone's view exists
3375	 *   - A zone with the right name exists in the view
3376	 *   - The zone is compatible with the config
3377	 *     options (e.g., an existing master zone cannot
3378	 *     be reused if the options specify a slave zone)
3379	 */
3380	result = dns_viewlist_find(&ns_g_server->viewlist,
3381				   view->name, view->rdclass,
3382				   &pview);
3383	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3384		goto cleanup;
3385	if (pview != NULL)
3386		result = dns_view_findzone(pview, origin, &zone);
3387	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3388		goto cleanup;
3389	if (zone != NULL && !ns_zone_reusable(zone, zconfig))
3390		dns_zone_detach(&zone);
3391
3392	if (zone != NULL) {
3393		/*
3394		 * We found a reusable zone.  Make it use the
3395		 * new view.
3396		 */
3397		dns_zone_setview(zone, view);
3398		if (view->acache != NULL)
3399			dns_zone_setacache(zone, view->acache);
3400	} else {
3401		/*
3402		 * We cannot reuse an existing zone, we have
3403		 * to create a new one.
3404		 */
3405		CHECK(dns_zone_create(&zone, mctx));
3406		CHECK(dns_zone_setorigin(zone, origin));
3407		dns_zone_setview(zone, view);
3408		if (view->acache != NULL)
3409			dns_zone_setacache(zone, view->acache);
3410		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
3411		dns_zone_setstats(zone, ns_g_server->zonestats);
3412	}
3413
3414	/*
3415	 * If the zone contains a 'forwarders' statement, configure
3416	 * selective forwarding.
3417	 */
3418	forwarders = NULL;
3419	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
3420	{
3421		forwardtype = NULL;
3422		(void)cfg_map_get(zoptions, "forward", &forwardtype);
3423		CHECK(configure_forward(config, view, origin, forwarders,
3424					forwardtype));
3425	}
3426
3427	/*
3428	 * Stub and forward zones may also refer to delegation only points.
3429	 */
3430	only = NULL;
3431	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
3432	{
3433		if (cfg_obj_asboolean(only))
3434			CHECK(dns_view_adddelegationonly(view, origin));
3435	}
3436
3437	/*
3438	 * Mark whether the zone was originally added at runtime or not
3439	 */
3440	dns_zone_setadded(zone, added);
3441
3442	/*
3443	 * Configure the zone.
3444	 */
3445	CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
3446
3447	/*
3448	 * Add the zone to its view in the new view list.
3449	 */
3450	CHECK(dns_view_addzone(view, zone));
3451
3452 cleanup:
3453	if (zone != NULL)
3454		dns_zone_detach(&zone);
3455	if (pview != NULL)
3456		dns_view_detach(&pview);
3457
3458	return (result);
3459}
3460
3461/*
3462 * Configure built-in zone for storing managed-key data.
3463 */
3464
3465#define KEYZONE "managed-keys.bind"
3466#define MKEYS ".mkeys"
3467
3468static isc_result_t
3469add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
3470	isc_result_t result;
3471	dns_view_t *pview = NULL;
3472	dns_zone_t *zone = NULL;
3473	dns_acl_t *none = NULL;
3474	char filename[PATH_MAX];
3475	char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)];
3476	int n;
3477
3478	REQUIRE(view != NULL);
3479
3480	/* See if we can re-use an existing keydata zone. */
3481	result = dns_viewlist_find(&ns_g_server->viewlist,
3482				   view->name, view->rdclass,
3483				   &pview);
3484	if (result != ISC_R_NOTFOUND &&
3485	    result != ISC_R_SUCCESS)
3486		return (result);
3487
3488	if (pview != NULL && pview->managed_keys != NULL) {
3489		dns_zone_attach(pview->managed_keys, &view->managed_keys);
3490		dns_zone_setview(pview->managed_keys, view);
3491		dns_view_detach(&pview);
3492		return (ISC_R_SUCCESS);
3493	}
3494
3495	/* No existing keydata zone was found; create one */
3496	CHECK(dns_zone_create(&zone, mctx));
3497	CHECK(dns_zone_setorigin(zone, dns_rootname));
3498
3499	isc_sha256_data((void *)view->name, strlen(view->name), buffer);
3500	strcat(buffer, MKEYS);
3501	n = snprintf(filename, sizeof(filename), "%s%s%s",
3502		     directory ? directory : "", directory ? "/" : "",
3503		     strcmp(view->name, "_default") == 0 ? KEYZONE : buffer);
3504	if (n < 0 || (size_t)n >= sizeof(filename)) {
3505		result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE;
3506		goto cleanup;
3507	}
3508	CHECK(dns_zone_setfile(zone, filename));
3509
3510	dns_zone_setview(zone, view);
3511	dns_zone_settype(zone, dns_zone_key);
3512	dns_zone_setclass(zone, view->rdclass);
3513
3514	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
3515
3516	if (view->acache != NULL)
3517		dns_zone_setacache(zone, view->acache);
3518
3519	CHECK(dns_acl_none(mctx, &none));
3520	dns_zone_setqueryacl(zone, none);
3521	dns_zone_setqueryonacl(zone, none);
3522	dns_acl_detach(&none);
3523
3524	dns_zone_setdialup(zone, dns_dialuptype_no);
3525	dns_zone_setnotifytype(zone, dns_notifytype_no);
3526	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
3527	dns_zone_setjournalsize(zone, 0);
3528
3529	dns_zone_setstats(zone, ns_g_server->zonestats);
3530	CHECK(setquerystats(zone, mctx, ISC_FALSE));
3531
3532	if (view->managed_keys != NULL)
3533		dns_zone_detach(&view->managed_keys);
3534	dns_zone_attach(zone, &view->managed_keys);
3535
3536	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3537		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3538		      "set up managed keys zone for view %s, file '%s'",
3539		      view->name, filename);
3540
3541cleanup:
3542	if (zone != NULL)
3543		dns_zone_detach(&zone);
3544	if (none != NULL)
3545		dns_acl_detach(&none);
3546
3547	return (result);
3548}
3549
3550/*
3551 * Configure a single server quota.
3552 */
3553static void
3554configure_server_quota(const cfg_obj_t **maps, const char *name,
3555		       isc_quota_t *quota)
3556{
3557	const cfg_obj_t *obj = NULL;
3558	isc_result_t result;
3559
3560	result = ns_config_get(maps, name, &obj);
3561	INSIST(result == ISC_R_SUCCESS);
3562	isc_quota_max(quota, cfg_obj_asuint32(obj));
3563}
3564
3565/*
3566 * This function is called as soon as the 'directory' statement has been
3567 * parsed.  This can be extended to support other options if necessary.
3568 */
3569static isc_result_t
3570directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
3571	isc_result_t result;
3572	const char *directory;
3573
3574	REQUIRE(strcasecmp("directory", clausename) == 0);
3575
3576	UNUSED(arg);
3577	UNUSED(clausename);
3578
3579	/*
3580	 * Change directory.
3581	 */
3582	directory = cfg_obj_asstring(obj);
3583
3584	if (! isc_file_ischdiridempotent(directory))
3585		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
3586			    "option 'directory' contains relative path '%s'",
3587			    directory);
3588
3589	result = isc_dir_chdir(directory);
3590	if (result != ISC_R_SUCCESS) {
3591		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
3592			    "change directory to '%s' failed: %s",
3593			    directory, isc_result_totext(result));
3594		return (result);
3595	}
3596
3597	return (ISC_R_SUCCESS);
3598}
3599
3600static void
3601scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
3602	isc_boolean_t match_mapped = server->aclenv.match_mapped;
3603
3604	ns_interfacemgr_scan(server->interfacemgr, verbose);
3605	/*
3606	 * Update the "localhost" and "localnets" ACLs to match the
3607	 * current set of network interfaces.
3608	 */
3609	dns_aclenv_copy(&server->aclenv,
3610			ns_interfacemgr_getaclenv(server->interfacemgr));
3611
3612	server->aclenv.match_mapped = match_mapped;
3613}
3614
3615static isc_result_t
3616add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
3617	      isc_boolean_t wcardport_ok)
3618{
3619	ns_listenelt_t *lelt = NULL;
3620	dns_acl_t *src_acl = NULL;
3621	isc_result_t result;
3622	isc_sockaddr_t any_sa6;
3623	isc_netaddr_t netaddr;
3624
3625	REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
3626
3627	isc_sockaddr_any6(&any_sa6);
3628	if (!isc_sockaddr_equal(&any_sa6, addr) &&
3629	    (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
3630		isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
3631
3632		result = dns_acl_create(mctx, 0, &src_acl);
3633		if (result != ISC_R_SUCCESS)
3634			return (result);
3635
3636		result = dns_iptable_addprefix(src_acl->iptable,
3637					       &netaddr, 128, ISC_TRUE);
3638		if (result != ISC_R_SUCCESS)
3639			goto clean;
3640
3641		result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
3642					     src_acl, &lelt);
3643		if (result != ISC_R_SUCCESS)
3644			goto clean;
3645		ISC_LIST_APPEND(list->elts, lelt, link);
3646	}
3647
3648	return (ISC_R_SUCCESS);
3649
3650 clean:
3651	INSIST(lelt == NULL);
3652	dns_acl_detach(&src_acl);
3653
3654	return (result);
3655}
3656
3657/*
3658 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
3659 * to update the listening interfaces accordingly.
3660 * We currently only consider IPv6, because this only affects IPv6 wildcard
3661 * sockets.
3662 */
3663static void
3664adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
3665	isc_result_t result;
3666	ns_listenlist_t *list = NULL;
3667	dns_view_t *view;
3668	dns_zone_t *zone, *next;
3669	isc_sockaddr_t addr, *addrp;
3670
3671	result = ns_listenlist_create(mctx, &list);
3672	if (result != ISC_R_SUCCESS)
3673		return;
3674
3675	for (view = ISC_LIST_HEAD(server->viewlist);
3676	     view != NULL;
3677	     view = ISC_LIST_NEXT(view, link)) {
3678		dns_dispatch_t *dispatch6;
3679
3680		dispatch6 = dns_resolver_dispatchv6(view->resolver);
3681		if (dispatch6 == NULL)
3682			continue;
3683		result = dns_dispatch_getlocaladdress(dispatch6, &addr);
3684		if (result != ISC_R_SUCCESS)
3685			goto fail;
3686
3687		/*
3688		 * We always add non-wildcard address regardless of whether
3689		 * the port is 'any' (the fourth arg is TRUE): if the port is
3690		 * specific, we need to add it since it may conflict with a
3691		 * listening interface; if it's zero, we'll dynamically open
3692		 * query ports, and some of them may override an existing
3693		 * wildcard IPv6 port.
3694		 */
3695		result = add_listenelt(mctx, list, &addr, ISC_TRUE);
3696		if (result != ISC_R_SUCCESS)
3697			goto fail;
3698	}
3699
3700	zone = NULL;
3701	for (result = dns_zone_first(server->zonemgr, &zone);
3702	     result == ISC_R_SUCCESS;
3703	     next = NULL, result = dns_zone_next(zone, &next), zone = next) {
3704		dns_view_t *zoneview;
3705
3706		/*
3707		 * At this point the zone list may contain a stale zone
3708		 * just removed from the configuration.  To see the validity,
3709		 * check if the corresponding view is in our current view list.
3710		 * There may also be old zones that are still in the process
3711		 * of shutting down and have detached from their old view
3712		 * (zoneview == NULL).
3713		 */
3714		zoneview = dns_zone_getview(zone);
3715		if (zoneview == NULL)
3716			continue;
3717		for (view = ISC_LIST_HEAD(server->viewlist);
3718		     view != NULL && view != zoneview;
3719		     view = ISC_LIST_NEXT(view, link))
3720			;
3721		if (view == NULL)
3722			continue;
3723
3724		addrp = dns_zone_getnotifysrc6(zone);
3725		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
3726		if (result != ISC_R_SUCCESS)
3727			goto fail;
3728
3729		addrp = dns_zone_getxfrsource6(zone);
3730		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
3731		if (result != ISC_R_SUCCESS)
3732			goto fail;
3733	}
3734
3735	ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
3736
3737 clean:
3738	ns_listenlist_detach(&list);
3739	return;
3740
3741 fail:
3742	/*
3743	 * Even when we failed the procedure, most of other interfaces
3744	 * should work correctly.  We therefore just warn it.
3745	 */
3746	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3747		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3748		      "could not adjust the listen-on list; "
3749		      "some interfaces may not work");
3750	goto clean;
3751}
3752
3753/*
3754 * This event callback is invoked to do periodic network
3755 * interface scanning.
3756 */
3757static void
3758interface_timer_tick(isc_task_t *task, isc_event_t *event) {
3759	isc_result_t result;
3760	ns_server_t *server = (ns_server_t *) event->ev_arg;
3761	INSIST(task == server->task);
3762	UNUSED(task);
3763	isc_event_free(&event);
3764	/*
3765	 * XXX should scan interfaces unlocked and get exclusive access
3766	 * only to replace ACLs.
3767	 */
3768	result = isc_task_beginexclusive(server->task);
3769	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3770	scan_interfaces(server, ISC_FALSE);
3771	isc_task_endexclusive(server->task);
3772}
3773
3774static void
3775heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
3776	ns_server_t *server = (ns_server_t *) event->ev_arg;
3777	dns_view_t *view;
3778
3779	UNUSED(task);
3780	isc_event_free(&event);
3781	view = ISC_LIST_HEAD(server->viewlist);
3782	while (view != NULL) {
3783		dns_view_dialup(view);
3784		view = ISC_LIST_NEXT(view, link);
3785	}
3786}
3787
3788static void
3789pps_timer_tick(isc_task_t *task, isc_event_t *event) {
3790	static unsigned int oldrequests = 0;
3791	unsigned int requests = ns_client_requests;
3792
3793	UNUSED(task);
3794	isc_event_free(&event);
3795
3796	/*
3797	 * Don't worry about wrapping as the overflow result will be right.
3798	 */
3799	dns_pps = (requests - oldrequests) / 1200;
3800	oldrequests = requests;
3801}
3802
3803/*
3804 * Replace the current value of '*field', a dynamically allocated
3805 * string or NULL, with a dynamically allocated copy of the
3806 * null-terminated string pointed to by 'value', or NULL.
3807 */
3808static isc_result_t
3809setstring(ns_server_t *server, char **field, const char *value) {
3810	char *copy;
3811
3812	if (value != NULL) {
3813		copy = isc_mem_strdup(server->mctx, value);
3814		if (copy == NULL)
3815			return (ISC_R_NOMEMORY);
3816	} else {
3817		copy = NULL;
3818	}
3819
3820	if (*field != NULL)
3821		isc_mem_free(server->mctx, *field);
3822
3823	*field = copy;
3824	return (ISC_R_SUCCESS);
3825}
3826
3827/*
3828 * Replace the current value of '*field', a dynamically allocated
3829 * string or NULL, with another dynamically allocated string
3830 * or NULL if whether 'obj' is a string or void value, respectively.
3831 */
3832static isc_result_t
3833setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
3834	if (cfg_obj_isvoid(obj))
3835		return (setstring(server, field, NULL));
3836	else
3837		return (setstring(server, field, cfg_obj_asstring(obj)));
3838}
3839
3840static void
3841set_limit(const cfg_obj_t **maps, const char *configname,
3842	  const char *description, isc_resource_t resourceid,
3843	  isc_resourcevalue_t defaultvalue)
3844{
3845	const cfg_obj_t *obj = NULL;
3846	const char *resource;
3847	isc_resourcevalue_t value;
3848	isc_result_t result;
3849
3850	if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
3851		return;
3852
3853	if (cfg_obj_isstring(obj)) {
3854		resource = cfg_obj_asstring(obj);
3855		if (strcasecmp(resource, "unlimited") == 0)
3856			value = ISC_RESOURCE_UNLIMITED;
3857		else {
3858			INSIST(strcasecmp(resource, "default") == 0);
3859			value = defaultvalue;
3860		}
3861	} else
3862		value = cfg_obj_asuint64(obj);
3863
3864	result = isc_resource_setlimit(resourceid, value);
3865	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3866		      result == ISC_R_SUCCESS ?
3867			ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
3868		      "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
3869		      description, value, isc_result_totext(result));
3870}
3871
3872#define SETLIMIT(cfgvar, resource, description) \
3873	set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
3874		  ns_g_init ## resource)
3875
3876static void
3877set_limits(const cfg_obj_t **maps) {
3878	SETLIMIT("stacksize", stacksize, "stack size");
3879	SETLIMIT("datasize", datasize, "data size");
3880	SETLIMIT("coresize", coresize, "core size");
3881	SETLIMIT("files", openfiles, "open files");
3882}
3883
3884static void
3885portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
3886		 isc_boolean_t positive)
3887{
3888	const cfg_listelt_t *element;
3889
3890	for (element = cfg_list_first(ports);
3891	     element != NULL;
3892	     element = cfg_list_next(element)) {
3893		const cfg_obj_t *obj = cfg_listelt_value(element);
3894
3895		if (cfg_obj_isuint32(obj)) {
3896			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
3897
3898			if (positive)
3899				isc_portset_add(portset, port);
3900			else
3901				isc_portset_remove(portset, port);
3902		} else {
3903			const cfg_obj_t *obj_loport, *obj_hiport;
3904			in_port_t loport, hiport;
3905
3906			obj_loport = cfg_tuple_get(obj, "loport");
3907			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
3908			obj_hiport = cfg_tuple_get(obj, "hiport");
3909			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
3910
3911			if (positive)
3912				isc_portset_addrange(portset, loport, hiport);
3913			else {
3914				isc_portset_removerange(portset, loport,
3915							hiport);
3916			}
3917		}
3918	}
3919}
3920
3921static isc_result_t
3922removed(dns_zone_t *zone, void *uap) {
3923	const char *type;
3924
3925	if (dns_zone_getview(zone) != uap)
3926		return (ISC_R_SUCCESS);
3927
3928	switch (dns_zone_gettype(zone)) {
3929	case dns_zone_master:
3930		type = "master";
3931		break;
3932	case dns_zone_slave:
3933		type = "slave";
3934		break;
3935	case dns_zone_stub:
3936		type = "stub";
3937		break;
3938	default:
3939		type = "other";
3940		break;
3941	}
3942	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
3943	return (ISC_R_SUCCESS);
3944}
3945
3946static void
3947cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
3948	if (server->session_keyfile != NULL) {
3949		isc_file_remove(server->session_keyfile);
3950		isc_mem_free(mctx, server->session_keyfile);
3951		server->session_keyfile = NULL;
3952	}
3953
3954	if (server->session_keyname != NULL) {
3955		if (dns_name_dynamic(server->session_keyname))
3956			dns_name_free(server->session_keyname, mctx);
3957		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
3958		server->session_keyname = NULL;
3959	}
3960
3961	if (server->sessionkey != NULL)
3962		dns_tsigkey_detach(&server->sessionkey);
3963
3964	server->session_keyalg = DST_ALG_UNKNOWN;
3965	server->session_keybits = 0;
3966}
3967
3968static isc_result_t
3969generate_session_key(const char *filename, const char *keynamestr,
3970		     dns_name_t *keyname, const char *algstr,
3971		     dns_name_t *algname, unsigned int algtype,
3972		     isc_uint16_t bits, isc_mem_t *mctx,
3973		     dns_tsigkey_t **tsigkeyp)
3974{
3975	isc_result_t result = ISC_R_SUCCESS;
3976	dst_key_t *key = NULL;
3977	isc_buffer_t key_txtbuffer;
3978	isc_buffer_t key_rawbuffer;
3979	char key_txtsecret[256];
3980	char key_rawsecret[64];
3981	isc_region_t key_rawregion;
3982	isc_stdtime_t now;
3983	dns_tsigkey_t *tsigkey = NULL;
3984	FILE *fp = NULL;
3985
3986	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3987		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3988		      "generating session key for dynamic DNS");
3989
3990	/* generate key */
3991	result = dst_key_generate(keyname, algtype, bits, 1, 0,
3992				  DNS_KEYPROTO_ANY, dns_rdataclass_in,
3993				  mctx, &key);
3994	if (result != ISC_R_SUCCESS)
3995		return (result);
3996
3997	/*
3998	 * Dump the key to the buffer for later use.  Should be done before
3999	 * we transfer the ownership of key to tsigkey.
4000	 */
4001	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
4002	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
4003
4004	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
4005	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
4006	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
4007
4008	/* Store the key in tsigkey. */
4009	isc_stdtime_get(&now);
4010	CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
4011					ISC_FALSE, NULL, now, now, mctx, NULL,
4012					&tsigkey));
4013
4014	/* Dump the key to the key file. */
4015	fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
4016	if (fp == NULL) {
4017		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4018			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4019			      "could not create %s", filename);
4020		result = ISC_R_NOPERM;
4021		goto cleanup;
4022	}
4023
4024	fprintf(fp, "key \"%s\" {\n"
4025		"\talgorithm %s;\n"
4026		"\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
4027		(int) isc_buffer_usedlength(&key_txtbuffer),
4028		(char*) isc_buffer_base(&key_txtbuffer));
4029
4030	RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS);
4031	RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS);
4032
4033	dst_key_free(&key);
4034
4035	*tsigkeyp = tsigkey;
4036
4037	return (ISC_R_SUCCESS);
4038
4039  cleanup:
4040	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4041		      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4042		      "failed to generate session key "
4043		      "for dynamic DNS: %s", isc_result_totext(result));
4044	if (tsigkey != NULL)
4045		dns_tsigkey_detach(&tsigkey);
4046	if (key != NULL)
4047		dst_key_free(&key);
4048
4049	return (result);
4050}
4051
4052static isc_result_t
4053configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
4054		      isc_mem_t *mctx)
4055{
4056	const char *keyfile, *keynamestr, *algstr;
4057	unsigned int algtype;
4058	dns_fixedname_t fname;
4059	dns_name_t *keyname, *algname;
4060	isc_buffer_t buffer;
4061	isc_uint16_t bits;
4062	const cfg_obj_t *obj;
4063	isc_boolean_t need_deleteold = ISC_FALSE;
4064	isc_boolean_t need_createnew = ISC_FALSE;
4065	isc_result_t result;
4066
4067	obj = NULL;
4068	result = ns_config_get(maps, "session-keyfile", &obj);
4069	if (result == ISC_R_SUCCESS) {
4070		if (cfg_obj_isvoid(obj))
4071			keyfile = NULL; /* disable it */
4072		else
4073			keyfile = cfg_obj_asstring(obj);
4074	} else
4075		keyfile = ns_g_defaultsessionkeyfile;
4076
4077	obj = NULL;
4078	result = ns_config_get(maps, "session-keyname", &obj);
4079	INSIST(result == ISC_R_SUCCESS);
4080	keynamestr = cfg_obj_asstring(obj);
4081	dns_fixedname_init(&fname);
4082	isc_buffer_init(&buffer, keynamestr, strlen(keynamestr));
4083	isc_buffer_add(&buffer, strlen(keynamestr));
4084	keyname = dns_fixedname_name(&fname);
4085	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
4086	if (result != ISC_R_SUCCESS)
4087		return (result);
4088
4089	obj = NULL;
4090	result = ns_config_get(maps, "session-keyalg", &obj);
4091	INSIST(result == ISC_R_SUCCESS);
4092	algstr = cfg_obj_asstring(obj);
4093	algname = NULL;
4094	result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
4095	if (result != ISC_R_SUCCESS) {
4096		const char *s = " (keeping current key)";
4097
4098		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
4099			    "unsupported or unknown algorithm '%s'%s",
4100			    algstr,
4101			    server->session_keyfile != NULL ? s : "");
4102		return (result);
4103	}
4104
4105	/* See if we need to (re)generate a new key. */
4106	if (keyfile == NULL) {
4107		if (server->session_keyfile != NULL)
4108			need_deleteold = ISC_TRUE;
4109	} else if (server->session_keyfile == NULL)
4110		need_createnew = ISC_TRUE;
4111	else if (strcmp(keyfile, server->session_keyfile) != 0 ||
4112		 !dns_name_equal(server->session_keyname, keyname) ||
4113		 server->session_keyalg != algtype ||
4114		 server->session_keybits != bits) {
4115		need_deleteold = ISC_TRUE;
4116		need_createnew = ISC_TRUE;
4117	}
4118
4119	if (need_deleteold) {
4120		INSIST(server->session_keyfile != NULL);
4121		INSIST(server->session_keyname != NULL);
4122		INSIST(server->sessionkey != NULL);
4123
4124		cleanup_session_key(server, mctx);
4125	}
4126
4127	if (need_createnew) {
4128		INSIST(server->sessionkey == NULL);
4129		INSIST(server->session_keyfile == NULL);
4130		INSIST(server->session_keyname == NULL);
4131		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
4132		INSIST(server->session_keybits == 0);
4133
4134		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
4135		if (server->session_keyname == NULL)
4136			goto cleanup;
4137		dns_name_init(server->session_keyname, NULL);
4138		CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
4139
4140		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
4141		if (server->session_keyfile == NULL)
4142			goto cleanup;
4143
4144		server->session_keyalg = algtype;
4145		server->session_keybits = bits;
4146
4147		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
4148					   algname, algtype, bits, mctx,
4149					   &server->sessionkey));
4150	}
4151
4152	return (result);
4153
4154  cleanup:
4155	cleanup_session_key(server, mctx);
4156	return (result);
4157}
4158
4159static isc_result_t
4160setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
4161	       cfg_parser_t *parser, cfg_aclconfctx_t *actx)
4162{
4163	isc_result_t result = ISC_R_SUCCESS;
4164	isc_boolean_t allow = ISC_FALSE;
4165	struct cfg_context *nzcfg = NULL;
4166	cfg_parser_t *nzparser = NULL;
4167	cfg_obj_t *nzconfig = NULL;
4168	const cfg_obj_t *maps[4];
4169	const cfg_obj_t *options = NULL, *voptions = NULL;
4170	const cfg_obj_t *nz = NULL;
4171	int i = 0;
4172
4173	REQUIRE (config != NULL);
4174
4175	if (vconfig != NULL)
4176		voptions = cfg_tuple_get(vconfig, "options");
4177	if (voptions != NULL)
4178		maps[i++] = voptions;
4179	result = cfg_map_get(config, "options", &options);
4180	if (result == ISC_R_SUCCESS)
4181		maps[i++] = options;
4182	maps[i++] = ns_g_defaults;
4183	maps[i] = NULL;
4184
4185	result = ns_config_get(maps, "allow-new-zones", &nz);
4186	if (result == ISC_R_SUCCESS)
4187		allow = cfg_obj_asboolean(nz);
4188
4189	if (!allow) {
4190		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4191		return (ISC_R_SUCCESS);
4192	}
4193
4194	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
4195	if (nzcfg == NULL) {
4196		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4197		return (ISC_R_NOMEMORY);
4198	}
4199
4200	dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
4201
4202	memset(nzcfg, 0, sizeof(*nzcfg));
4203	isc_mem_attach(view->mctx, &nzcfg->mctx);
4204	cfg_obj_attach(config, &nzcfg->config);
4205	cfg_parser_attach(parser, &nzcfg->parser);
4206	cfg_aclconfctx_attach(actx, &nzcfg->actx);
4207
4208	/*
4209	 * Attempt to create a parser and parse the newzones
4210	 * file.  If successful, preserve both; otherwise leave
4211	 * them NULL.
4212	 */
4213	result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser);
4214	if (result == ISC_R_SUCCESS)
4215		result = cfg_parse_file(nzparser, view->new_zone_file,
4216					&cfg_type_newzones, &nzconfig);
4217	if (result == ISC_R_SUCCESS) {
4218		cfg_parser_attach(nzparser, &nzcfg->nzparser);
4219		cfg_obj_attach(nzconfig, &nzcfg->nzconfig);
4220	}
4221
4222	if (nzparser != NULL) {
4223		if (nzconfig != NULL)
4224			cfg_obj_destroy(nzparser, &nzconfig);
4225		cfg_parser_destroy(&nzparser);
4226	}
4227
4228	return (ISC_R_SUCCESS);
4229}
4230
4231static int
4232count_zones(const cfg_obj_t *conf) {
4233	const cfg_obj_t *zonelist = NULL;
4234	const cfg_listelt_t *element;
4235	int n = 0;
4236
4237	REQUIRE(conf != NULL);
4238
4239	cfg_map_get(conf, "zone", &zonelist);
4240	for (element = cfg_list_first(zonelist);
4241	     element != NULL;
4242	     element = cfg_list_next(element))
4243		n++;
4244
4245	return (n);
4246}
4247
4248static isc_result_t
4249load_configuration(const char *filename, ns_server_t *server,
4250		   isc_boolean_t first_time)
4251{
4252	cfg_obj_t *config = NULL, *bindkeys = NULL;
4253	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
4254	const cfg_listelt_t *element;
4255	const cfg_obj_t *builtin_views;
4256	const cfg_obj_t *maps[3];
4257	const cfg_obj_t *obj;
4258	const cfg_obj_t *options;
4259	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
4260	const cfg_obj_t *views;
4261	dns_view_t *view = NULL;
4262	dns_view_t *view_next;
4263	dns_viewlist_t tmpviewlist;
4264	dns_viewlist_t viewlist, builtin_viewlist;
4265	in_port_t listen_port, udpport_low, udpport_high;
4266	int i;
4267	isc_interval_t interval;
4268	isc_portset_t *v4portset = NULL;
4269	isc_portset_t *v6portset = NULL;
4270	isc_resourcevalue_t nfiles;
4271	isc_result_t result;
4272	isc_uint32_t heartbeat_interval;
4273	isc_uint32_t interface_interval;
4274	isc_uint32_t reserved;
4275	isc_uint32_t udpsize;
4276	ns_cachelist_t cachelist, tmpcachelist;
4277	unsigned int maxsocks;
4278	ns_cache_t *nsc;
4279	struct cfg_context *nzctx;
4280	int num_zones = 0;
4281
4282	ISC_LIST_INIT(viewlist);
4283	ISC_LIST_INIT(builtin_viewlist);
4284	ISC_LIST_INIT(cachelist);
4285
4286	/* Ensure exclusive access to configuration data. */
4287	result = isc_task_beginexclusive(server->task);
4288	RUNTIME_CHECK(result == ISC_R_SUCCESS);
4289
4290	/* Create the ACL configuration context */
4291	if (ns_g_aclconfctx != NULL)
4292		cfg_aclconfctx_detach(&ns_g_aclconfctx);
4293	CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
4294
4295	/*
4296	 * Parse the global default pseudo-config file.
4297	 */
4298	if (first_time) {
4299		CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
4300		RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
4301					  &ns_g_defaults) == ISC_R_SUCCESS);
4302	}
4303
4304	/*
4305	 * Parse the configuration file using the new config code.
4306	 */
4307	result = ISC_R_FAILURE;
4308	config = NULL;
4309
4310	/*
4311	 * Unless this is lwresd with the -C option, parse the config file.
4312	 */
4313	if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
4314		isc_log_write(ns_g_lctx,
4315			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4316			      ISC_LOG_INFO, "loading configuration from '%s'",
4317			      filename);
4318		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4319		cfg_parser_setcallback(conf_parser, directory_callback, NULL);
4320		result = cfg_parse_file(conf_parser, filename,
4321					&cfg_type_namedconf, &config);
4322	}
4323
4324	/*
4325	 * If this is lwresd with the -C option, or lwresd with no -C or -c
4326	 * option where the above parsing failed, parse resolv.conf.
4327	 */
4328	if (ns_g_lwresdonly &&
4329	    (lwresd_g_useresolvconf ||
4330	     (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
4331	{
4332		isc_log_write(ns_g_lctx,
4333			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4334			      ISC_LOG_INFO, "loading configuration from '%s'",
4335			      lwresd_g_resolvconffile);
4336		if (conf_parser != NULL)
4337			cfg_parser_destroy(&conf_parser);
4338		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4339		result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
4340						    &config);
4341	}
4342	CHECK(result);
4343
4344	/*
4345	 * Check the validity of the configuration.
4346	 */
4347	CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
4348
4349	/*
4350	 * Fill in the maps array, used for resolving defaults.
4351	 */
4352	i = 0;
4353	options = NULL;
4354	result = cfg_map_get(config, "options", &options);
4355	if (result == ISC_R_SUCCESS)
4356		maps[i++] = options;
4357	maps[i++] = ns_g_defaults;
4358	maps[i] = NULL;
4359
4360	/*
4361	 * If bind.keys exists, load it.  If "dnssec-lookaside auto"
4362	 * is turned on, the keys found there will be used as default
4363	 * trust anchors.
4364	 */
4365	obj = NULL;
4366	result = ns_config_get(maps, "bindkeys-file", &obj);
4367	INSIST(result == ISC_R_SUCCESS);
4368	CHECKM(setstring(server, &server->bindkeysfile,
4369	       cfg_obj_asstring(obj)), "strdup");
4370
4371	if (access(server->bindkeysfile, R_OK) == 0) {
4372		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4373			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4374			      "reading built-in trusted "
4375			      "keys from file '%s'", server->bindkeysfile);
4376
4377		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
4378					&bindkeys_parser));
4379
4380		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
4381					&cfg_type_bindkeys, &bindkeys);
4382		CHECK(result);
4383	}
4384
4385	/*
4386	 * Set process limits, which (usually) needs to be done as root.
4387	 */
4388	set_limits(maps);
4389
4390	/*
4391	 * Check if max number of open sockets that the system allows is
4392	 * sufficiently large.	Failing this condition is not necessarily fatal,
4393	 * but may cause subsequent runtime failures for a busy recursive
4394	 * server.
4395	 */
4396	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
4397	if (result != ISC_R_SUCCESS)
4398		maxsocks = 0;
4399	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
4400	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
4401		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4402			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4403			      "max open files (%" ISC_PRINT_QUADFORMAT "u)"
4404			      " is smaller than max sockets (%u)",
4405			      nfiles, maxsocks);
4406	}
4407
4408	/*
4409	 * Set the number of socket reserved for TCP, stdio etc.
4410	 */
4411	obj = NULL;
4412	result = ns_config_get(maps, "reserved-sockets", &obj);
4413	INSIST(result == ISC_R_SUCCESS);
4414	reserved = cfg_obj_asuint32(obj);
4415	if (maxsocks != 0) {
4416		if (maxsocks < 128U)			/* Prevent underflow. */
4417			reserved = 0;
4418		else if (reserved > maxsocks - 128U)	/* Minimum UDP space. */
4419			reserved = maxsocks - 128;
4420	}
4421	/* Minimum TCP/stdio space. */
4422	if (reserved < 128U)
4423		reserved = 128;
4424	if (reserved + 128U > maxsocks && maxsocks != 0) {
4425		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4426			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4427			      "less than 128 UDP sockets available after "
4428			      "applying 'reserved-sockets' and 'maxsockets'");
4429	}
4430	isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
4431
4432	/*
4433	 * Configure various server options.
4434	 */
4435	configure_server_quota(maps, "transfers-out", &server->xfroutquota);
4436	configure_server_quota(maps, "tcp-clients", &server->tcpquota);
4437	configure_server_quota(maps, "recursive-clients",
4438			       &server->recursionquota);
4439	if (server->recursionquota.max > 1000)
4440		isc_quota_soft(&server->recursionquota,
4441			       server->recursionquota.max - 100);
4442	else
4443		isc_quota_soft(&server->recursionquota, 0);
4444
4445	CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
4446				 ns_g_aclconfctx, ns_g_mctx,
4447				 &server->blackholeacl));
4448	if (server->blackholeacl != NULL)
4449		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
4450					     server->blackholeacl);
4451
4452	obj = NULL;
4453	result = ns_config_get(maps, "match-mapped-addresses", &obj);
4454	INSIST(result == ISC_R_SUCCESS);
4455	server->aclenv.match_mapped = cfg_obj_asboolean(obj);
4456
4457	CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
4458	       "configuring statistics server(s)");
4459
4460	/*
4461	 * Configure sets of UDP query source ports.
4462	 */
4463	CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
4464	       "creating UDP port set");
4465	CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
4466	       "creating UDP port set");
4467
4468	usev4ports = NULL;
4469	usev6ports = NULL;
4470	avoidv4ports = NULL;
4471	avoidv6ports = NULL;
4472
4473	(void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
4474	if (usev4ports != NULL)
4475		portset_fromconf(v4portset, usev4ports, ISC_TRUE);
4476	else {
4477		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
4478					       &udpport_high),
4479		       "get the default UDP/IPv4 port range");
4480		if (udpport_low == udpport_high)
4481			isc_portset_add(v4portset, udpport_low);
4482		else {
4483			isc_portset_addrange(v4portset, udpport_low,
4484					     udpport_high);
4485		}
4486		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4487			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4488			      "using default UDP/IPv4 port range: [%d, %d]",
4489			      udpport_low, udpport_high);
4490	}
4491	(void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
4492	if (avoidv4ports != NULL)
4493		portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
4494
4495	(void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
4496	if (usev6ports != NULL)
4497		portset_fromconf(v6portset, usev6ports, ISC_TRUE);
4498	else {
4499		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
4500					       &udpport_high),
4501		       "get the default UDP/IPv6 port range");
4502		if (udpport_low == udpport_high)
4503			isc_portset_add(v6portset, udpport_low);
4504		else {
4505			isc_portset_addrange(v6portset, udpport_low,
4506					     udpport_high);
4507		}
4508		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4509			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4510			      "using default UDP/IPv6 port range: [%d, %d]",
4511			      udpport_low, udpport_high);
4512	}
4513	(void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
4514	if (avoidv6ports != NULL)
4515		portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
4516
4517	dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
4518
4519	/*
4520	 * Set the EDNS UDP size when we don't match a view.
4521	 */
4522	obj = NULL;
4523	result = ns_config_get(maps, "edns-udp-size", &obj);
4524	INSIST(result == ISC_R_SUCCESS);
4525	udpsize = cfg_obj_asuint32(obj);
4526	if (udpsize < 512)
4527		udpsize = 512;
4528	if (udpsize > 4096)
4529		udpsize = 4096;
4530	ns_g_udpsize = (isc_uint16_t)udpsize;
4531
4532	/*
4533	 * Configure the zone manager.
4534	 */
4535	obj = NULL;
4536	result = ns_config_get(maps, "transfers-in", &obj);
4537	INSIST(result == ISC_R_SUCCESS);
4538	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
4539
4540	obj = NULL;
4541	result = ns_config_get(maps, "transfers-per-ns", &obj);
4542	INSIST(result == ISC_R_SUCCESS);
4543	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
4544
4545	obj = NULL;
4546	result = ns_config_get(maps, "serial-query-rate", &obj);
4547	INSIST(result == ISC_R_SUCCESS);
4548	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
4549
4550	/*
4551	 * Determine which port to use for listening for incoming connections.
4552	 */
4553	if (ns_g_port != 0)
4554		listen_port = ns_g_port;
4555	else
4556		CHECKM(ns_config_getport(config, &listen_port), "port");
4557
4558	/*
4559	 * Find the listen queue depth.
4560	 */
4561	obj = NULL;
4562	result = ns_config_get(maps, "tcp-listen-queue", &obj);
4563	INSIST(result == ISC_R_SUCCESS);
4564	ns_g_listen = cfg_obj_asuint32(obj);
4565	if (ns_g_listen < 3)
4566		ns_g_listen = 3;
4567
4568	/*
4569	 * Configure the interface manager according to the "listen-on"
4570	 * statement.
4571	 */
4572	{
4573		const cfg_obj_t *clistenon = NULL;
4574		ns_listenlist_t *listenon = NULL;
4575
4576		clistenon = NULL;
4577		/*
4578		 * Even though listen-on is present in the default
4579		 * configuration, we can't use it here, since it isn't
4580		 * used if we're in lwresd mode.  This way is easier.
4581		 */
4582		if (options != NULL)
4583			(void)cfg_map_get(options, "listen-on", &clistenon);
4584		if (clistenon != NULL) {
4585			/* check return code? */
4586			(void)ns_listenlist_fromconfig(clistenon, config,
4587						       ns_g_aclconfctx,
4588						       ns_g_mctx, &listenon);
4589		} else if (!ns_g_lwresdonly) {
4590			/*
4591			 * Not specified, use default.
4592			 */
4593			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
4594						    ISC_TRUE, &listenon));
4595		}
4596		if (listenon != NULL) {
4597			ns_interfacemgr_setlistenon4(server->interfacemgr,
4598						     listenon);
4599			ns_listenlist_detach(&listenon);
4600		}
4601	}
4602	/*
4603	 * Ditto for IPv6.
4604	 */
4605	{
4606		const cfg_obj_t *clistenon = NULL;
4607		ns_listenlist_t *listenon = NULL;
4608
4609		if (options != NULL)
4610			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
4611		if (clistenon != NULL) {
4612			/* check return code? */
4613			(void)ns_listenlist_fromconfig(clistenon, config,
4614						       ns_g_aclconfctx,
4615						       ns_g_mctx, &listenon);
4616		} else if (!ns_g_lwresdonly) {
4617			isc_boolean_t enable;
4618			/*
4619			 * Not specified, use default.
4620			 */
4621			enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS);
4622			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
4623						    enable, &listenon));
4624		}
4625		if (listenon != NULL) {
4626			ns_interfacemgr_setlistenon6(server->interfacemgr,
4627						     listenon);
4628			ns_listenlist_detach(&listenon);
4629		}
4630	}
4631
4632	/*
4633	 * Rescan the interface list to pick up changes in the
4634	 * listen-on option.  It's important that we do this before we try
4635	 * to configure the query source, since the dispatcher we use might
4636	 * be shared with an interface.
4637	 */
4638	scan_interfaces(server, ISC_TRUE);
4639
4640	/*
4641	 * Arrange for further interface scanning to occur periodically
4642	 * as specified by the "interface-interval" option.
4643	 */
4644	obj = NULL;
4645	result = ns_config_get(maps, "interface-interval", &obj);
4646	INSIST(result == ISC_R_SUCCESS);
4647	interface_interval = cfg_obj_asuint32(obj) * 60;
4648	if (interface_interval == 0) {
4649		CHECK(isc_timer_reset(server->interface_timer,
4650				      isc_timertype_inactive,
4651				      NULL, NULL, ISC_TRUE));
4652	} else if (server->interface_interval != interface_interval) {
4653		isc_interval_set(&interval, interface_interval, 0);
4654		CHECK(isc_timer_reset(server->interface_timer,
4655				      isc_timertype_ticker,
4656				      NULL, &interval, ISC_FALSE));
4657	}
4658	server->interface_interval = interface_interval;
4659
4660	/*
4661	 * Configure the dialup heartbeat timer.
4662	 */
4663	obj = NULL;
4664	result = ns_config_get(maps, "heartbeat-interval", &obj);
4665	INSIST(result == ISC_R_SUCCESS);
4666	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
4667	if (heartbeat_interval == 0) {
4668		CHECK(isc_timer_reset(server->heartbeat_timer,
4669				      isc_timertype_inactive,
4670				      NULL, NULL, ISC_TRUE));
4671	} else if (server->heartbeat_interval != heartbeat_interval) {
4672		isc_interval_set(&interval, heartbeat_interval, 0);
4673		CHECK(isc_timer_reset(server->heartbeat_timer,
4674				      isc_timertype_ticker,
4675				      NULL, &interval, ISC_FALSE));
4676	}
4677	server->heartbeat_interval = heartbeat_interval;
4678
4679	isc_interval_set(&interval, 1200, 0);
4680	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
4681			      &interval, ISC_FALSE));
4682
4683	/*
4684	 * Write the PID file.
4685	 */
4686	obj = NULL;
4687	if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
4688		if (cfg_obj_isvoid(obj))
4689			ns_os_writepidfile(NULL, first_time);
4690		else
4691			ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
4692	else if (ns_g_lwresdonly)
4693		ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
4694	else
4695		ns_os_writepidfile(ns_g_defaultpidfile, first_time);
4696
4697	/*
4698	 * Configure the server-wide session key.  This must be done before
4699	 * configure views because zone configuration may need to know
4700	 * session-keyname.
4701	 *
4702	 * Failure of session key generation isn't fatal at this time; if it
4703	 * turns out that a session key is really needed but doesn't exist,
4704	 * we'll treat it as a fatal error then.
4705	 */
4706	(void)configure_session_key(maps, server, ns_g_mctx);
4707
4708	views = NULL;
4709	(void)cfg_map_get(config, "view", &views);
4710
4711	/*
4712	 * Create the views and count all the configured zones in
4713	 * order to correctly size the zone manager's task table.
4714	 * (We only count zones for configured views; the built-in
4715	 * "bind" view can be ignored as it only adds a negligible
4716	 * number of zones.)
4717	 *
4718	 * If we're allowing new zones, we need to be able to find the
4719	 * new zone file and count those as well.  So we setup the new
4720	 * zone configuration context, but otherwise view configuration
4721	 * waits until after the zone manager's task list has been sized.
4722	 */
4723	for (element = cfg_list_first(views);
4724	     element != NULL;
4725	     element = cfg_list_next(element))
4726	{
4727		cfg_obj_t *vconfig = cfg_listelt_value(element);
4728		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
4729		view = NULL;
4730
4731		CHECK(create_view(vconfig, &viewlist, &view));
4732		INSIST(view != NULL);
4733
4734		num_zones += count_zones(voptions);
4735		CHECK(setup_newzones(view, config, vconfig, conf_parser,
4736				     ns_g_aclconfctx));
4737
4738		nzctx = view->new_zone_config;
4739		if (nzctx != NULL && nzctx->nzconfig != NULL)
4740			num_zones += count_zones(nzctx->nzconfig);
4741
4742		dns_view_detach(&view);
4743	}
4744
4745	/*
4746	 * If there were no explicit views then we do the default
4747	 * view here.
4748	 */
4749	if (views == NULL) {
4750		CHECK(create_view(NULL, &viewlist, &view));
4751		INSIST(view != NULL);
4752
4753		num_zones = count_zones(config);
4754
4755		CHECK(setup_newzones(view, config, NULL,  conf_parser,
4756				     ns_g_aclconfctx));
4757
4758		nzctx = view->new_zone_config;
4759		if (nzctx != NULL && nzctx->nzconfig != NULL)
4760			num_zones += count_zones(nzctx->nzconfig);
4761
4762		dns_view_detach(&view);
4763	}
4764
4765	/*
4766	 * Zones have been counted; set the zone manager task pool size.
4767	 */
4768	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4769		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4770		      "sizing zone task pool based on %d zones", num_zones);
4771	CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
4772
4773	/*
4774	 * Configure and freeze all explicit views.  Explicit
4775	 * views that have zones were already created at parsing
4776	 * time, but views with no zones must be created here.
4777	 */
4778	for (element = cfg_list_first(views);
4779	     element != NULL;
4780	     element = cfg_list_next(element))
4781	{
4782		cfg_obj_t *vconfig = cfg_listelt_value(element);
4783
4784		view = NULL;
4785		CHECK(find_view(vconfig, &viewlist, &view));
4786		CHECK(configure_view(view, config, vconfig,
4787				     &cachelist, bindkeys, ns_g_mctx,
4788				     ns_g_aclconfctx, ISC_TRUE));
4789		dns_view_freeze(view);
4790		dns_view_detach(&view);
4791	}
4792
4793	/*
4794	 * Make sure we have a default view if and only if there
4795	 * were no explicit views.
4796	 */
4797	if (views == NULL) {
4798		view = NULL;
4799		CHECK(find_view(NULL, &viewlist, &view));
4800		CHECK(configure_view(view, config, NULL,
4801				     &cachelist, bindkeys,
4802				     ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
4803		dns_view_freeze(view);
4804		dns_view_detach(&view);
4805	}
4806
4807	/*
4808	 * Create (or recreate) the built-in views.
4809	 */
4810	builtin_views = NULL;
4811	RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
4812				  &builtin_views) == ISC_R_SUCCESS);
4813	for (element = cfg_list_first(builtin_views);
4814	     element != NULL;
4815	     element = cfg_list_next(element))
4816	{
4817		cfg_obj_t *vconfig = cfg_listelt_value(element);
4818
4819		CHECK(create_view(vconfig, &builtin_viewlist, &view));
4820		CHECK(configure_view(view, config, vconfig,
4821				     &cachelist, bindkeys,
4822				     ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
4823		dns_view_freeze(view);
4824		dns_view_detach(&view);
4825		view = NULL;
4826	}
4827
4828	/* Now combine the two viewlists into one */
4829	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
4830
4831	/* Swap our new view list with the production one. */
4832	tmpviewlist = server->viewlist;
4833	server->viewlist = viewlist;
4834	viewlist = tmpviewlist;
4835
4836	/* Make the view list available to each of the views */
4837	view = ISC_LIST_HEAD(server->viewlist);
4838	while (view != NULL) {
4839		view->viewlist = &server->viewlist;
4840		view = ISC_LIST_NEXT(view, link);
4841	}
4842
4843	/* Swap our new cache list with the production one. */
4844	tmpcachelist = server->cachelist;
4845	server->cachelist = cachelist;
4846	cachelist = tmpcachelist;
4847
4848	/* Load the TKEY information from the configuration. */
4849	if (options != NULL) {
4850		dns_tkeyctx_t *t = NULL;
4851		CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
4852					     &t),
4853		       "configuring TKEY");
4854		if (server->tkeyctx != NULL)
4855			dns_tkeyctx_destroy(&server->tkeyctx);
4856		server->tkeyctx = t;
4857	}
4858
4859	/*
4860	 * Bind the control port(s).
4861	 */
4862	CHECKM(ns_controls_configure(ns_g_server->controls, config,
4863				     ns_g_aclconfctx),
4864	       "binding control channel(s)");
4865
4866	/*
4867	 * Bind the lwresd port(s).
4868	 */
4869	CHECKM(ns_lwresd_configure(ns_g_mctx, config),
4870	       "binding lightweight resolver ports");
4871
4872	/*
4873	 * Open the source of entropy.
4874	 */
4875	if (first_time) {
4876		obj = NULL;
4877		result = ns_config_get(maps, "random-device", &obj);
4878		if (result != ISC_R_SUCCESS) {
4879			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4880				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4881				      "no source of entropy found");
4882		} else {
4883			const char *randomdev = cfg_obj_asstring(obj);
4884			result = isc_entropy_createfilesource(ns_g_entropy,
4885							      randomdev);
4886			if (result != ISC_R_SUCCESS)
4887				isc_log_write(ns_g_lctx,
4888					      NS_LOGCATEGORY_GENERAL,
4889					      NS_LOGMODULE_SERVER,
4890					      ISC_LOG_INFO,
4891					      "could not open entropy source "
4892					      "%s: %s",
4893					      randomdev,
4894					      isc_result_totext(result));
4895#ifdef PATH_RANDOMDEV
4896			if (ns_g_fallbackentropy != NULL) {
4897				if (result != ISC_R_SUCCESS) {
4898					isc_log_write(ns_g_lctx,
4899						      NS_LOGCATEGORY_GENERAL,
4900						      NS_LOGMODULE_SERVER,
4901						      ISC_LOG_INFO,
4902						      "using pre-chroot entropy source "
4903						      "%s",
4904						      PATH_RANDOMDEV);
4905					isc_entropy_detach(&ns_g_entropy);
4906					isc_entropy_attach(ns_g_fallbackentropy,
4907							   &ns_g_entropy);
4908				}
4909				isc_entropy_detach(&ns_g_fallbackentropy);
4910			}
4911#endif
4912		}
4913	}
4914
4915	/*
4916	 * Relinquish root privileges.
4917	 */
4918	if (first_time)
4919		ns_os_changeuser();
4920
4921	/*
4922	 * Check that the working directory is writable.
4923	 */
4924	if (access(".", W_OK) != 0) {
4925		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4926			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4927			      "the working directory is not writable");
4928	}
4929
4930	/*
4931	 * Configure the logging system.
4932	 *
4933	 * Do this after changing UID to make sure that any log
4934	 * files specified in named.conf get created by the
4935	 * unprivileged user, not root.
4936	 */
4937	if (ns_g_logstderr) {
4938		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4939			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4940			      "ignoring config file logging "
4941			      "statement due to -g option");
4942	} else {
4943		const cfg_obj_t *logobj = NULL;
4944		isc_logconfig_t *logc = NULL;
4945
4946		CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
4947		       "creating new logging configuration");
4948
4949		logobj = NULL;
4950		(void)cfg_map_get(config, "logging", &logobj);
4951		if (logobj != NULL) {
4952			CHECKM(ns_log_configure(logc, logobj),
4953			       "configuring logging");
4954		} else {
4955			CHECKM(ns_log_setdefaultchannels(logc),
4956			       "setting up default logging channels");
4957			CHECKM(ns_log_setunmatchedcategory(logc),
4958			       "setting up default 'category unmatched'");
4959			CHECKM(ns_log_setdefaultcategory(logc),
4960			       "setting up default 'category default'");
4961		}
4962
4963		result = isc_logconfig_use(ns_g_lctx, logc);
4964		if (result != ISC_R_SUCCESS) {
4965			isc_logconfig_destroy(&logc);
4966			CHECKM(result, "installing logging configuration");
4967		}
4968
4969		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4970			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
4971			      "now using logging configuration from "
4972			      "config file");
4973	}
4974
4975	/*
4976	 * Set the default value of the query logging flag depending
4977	 * whether a "queries" category has been defined.  This is
4978	 * a disgusting hack, but we need to do this for BIND 8
4979	 * compatibility.
4980	 */
4981	if (first_time) {
4982		const cfg_obj_t *logobj = NULL;
4983		const cfg_obj_t *categories = NULL;
4984
4985		obj = NULL;
4986		if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
4987			server->log_queries = cfg_obj_asboolean(obj);
4988		} else {
4989
4990			(void)cfg_map_get(config, "logging", &logobj);
4991			if (logobj != NULL)
4992				(void)cfg_map_get(logobj, "category",
4993						  &categories);
4994			if (categories != NULL) {
4995				const cfg_listelt_t *element;
4996				for (element = cfg_list_first(categories);
4997				     element != NULL;
4998				     element = cfg_list_next(element))
4999				{
5000					const cfg_obj_t *catobj;
5001					const char *str;
5002
5003					obj = cfg_listelt_value(element);
5004					catobj = cfg_tuple_get(obj, "name");
5005					str = cfg_obj_asstring(catobj);
5006					if (strcasecmp(str, "queries") == 0)
5007						server->log_queries = ISC_TRUE;
5008				}
5009			}
5010		}
5011	}
5012
5013
5014	obj = NULL;
5015	if (options != NULL &&
5016	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
5017		ns_g_memstatistics = cfg_obj_asboolean(obj);
5018	else
5019		ns_g_memstatistics =
5020			ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
5021
5022	obj = NULL;
5023	if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
5024		ns_main_setmemstats(cfg_obj_asstring(obj));
5025	else if (ns_g_memstatistics)
5026		ns_main_setmemstats("named.memstats");
5027	else
5028		ns_main_setmemstats(NULL);
5029
5030	obj = NULL;
5031	result = ns_config_get(maps, "statistics-file", &obj);
5032	INSIST(result == ISC_R_SUCCESS);
5033	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
5034	       "strdup");
5035
5036	obj = NULL;
5037	result = ns_config_get(maps, "dump-file", &obj);
5038	INSIST(result == ISC_R_SUCCESS);
5039	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
5040	       "strdup");
5041
5042	obj = NULL;
5043	result = ns_config_get(maps, "secroots-file", &obj);
5044	INSIST(result == ISC_R_SUCCESS);
5045	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
5046	       "strdup");
5047
5048	obj = NULL;
5049	result = ns_config_get(maps, "recursing-file", &obj);
5050	INSIST(result == ISC_R_SUCCESS);
5051	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
5052	       "strdup");
5053
5054	obj = NULL;
5055	result = ns_config_get(maps, "version", &obj);
5056	if (result == ISC_R_SUCCESS) {
5057		CHECKM(setoptstring(server, &server->version, obj), "strdup");
5058		server->version_set = ISC_TRUE;
5059	} else {
5060		server->version_set = ISC_FALSE;
5061	}
5062
5063	obj = NULL;
5064	result = ns_config_get(maps, "hostname", &obj);
5065	if (result == ISC_R_SUCCESS) {
5066		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
5067		server->hostname_set = ISC_TRUE;
5068	} else {
5069		server->hostname_set = ISC_FALSE;
5070	}
5071
5072	obj = NULL;
5073	result = ns_config_get(maps, "server-id", &obj);
5074	server->server_usehostname = ISC_FALSE;
5075	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
5076		/* The parser translates "hostname" to ISC_TRUE */
5077		server->server_usehostname = cfg_obj_asboolean(obj);
5078		result = setstring(server, &server->server_id, NULL);
5079		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5080	} else if (result == ISC_R_SUCCESS) {
5081		/* Found a quoted string */
5082		CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
5083	} else {
5084		result = setstring(server, &server->server_id, NULL);
5085		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5086	}
5087
5088	obj = NULL;
5089	result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
5090	if (result == ISC_R_SUCCESS) {
5091		server->flushonshutdown = cfg_obj_asboolean(obj);
5092	} else {
5093		server->flushonshutdown = ISC_FALSE;
5094	}
5095
5096	result = ISC_R_SUCCESS;
5097
5098 cleanup:
5099	if (v4portset != NULL)
5100		isc_portset_destroy(ns_g_mctx, &v4portset);
5101
5102	if (v6portset != NULL)
5103		isc_portset_destroy(ns_g_mctx, &v6portset);
5104
5105	if (conf_parser != NULL) {
5106		if (config != NULL)
5107			cfg_obj_destroy(conf_parser, &config);
5108		cfg_parser_destroy(&conf_parser);
5109	}
5110
5111	if (bindkeys_parser != NULL) {
5112		if (bindkeys  != NULL)
5113			cfg_obj_destroy(bindkeys_parser, &bindkeys);
5114		cfg_parser_destroy(&bindkeys_parser);
5115	}
5116
5117	if (view != NULL)
5118		dns_view_detach(&view);
5119
5120	/*
5121	 * This cleans up either the old production view list
5122	 * or our temporary list depending on whether they
5123	 * were swapped above or not.
5124	 */
5125	for (view = ISC_LIST_HEAD(viewlist);
5126	     view != NULL;
5127	     view = view_next) {
5128		view_next = ISC_LIST_NEXT(view, link);
5129		ISC_LIST_UNLINK(viewlist, view, link);
5130		if (result == ISC_R_SUCCESS &&
5131		    strcmp(view->name, "_bind") != 0)
5132			(void)dns_zt_apply(view->zonetable, ISC_FALSE,
5133					   removed, view);
5134		dns_view_detach(&view);
5135	}
5136
5137	/* Same cleanup for cache list. */
5138	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
5139		ISC_LIST_UNLINK(cachelist, nsc, link);
5140		dns_cache_detach(&nsc->cache);
5141		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
5142	}
5143
5144	/*
5145	 * Adjust the listening interfaces in accordance with the source
5146	 * addresses specified in views and zones.
5147	 */
5148	if (isc_net_probeipv6() == ISC_R_SUCCESS)
5149		adjust_interfaces(server, ns_g_mctx);
5150
5151	/* Relinquish exclusive access to configuration data. */
5152	isc_task_endexclusive(server->task);
5153
5154	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5155		      ISC_LOG_DEBUG(1), "load_configuration: %s",
5156		      isc_result_totext(result));
5157
5158	return (result);
5159}
5160
5161static isc_result_t
5162load_zones(ns_server_t *server, isc_boolean_t stop) {
5163	isc_result_t result;
5164	dns_view_t *view;
5165
5166	result = isc_task_beginexclusive(server->task);
5167	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5168
5169	/*
5170	 * Load zone data from disk.
5171	 */
5172	for (view = ISC_LIST_HEAD(server->viewlist);
5173	     view != NULL;
5174	     view = ISC_LIST_NEXT(view, link))
5175	{
5176		CHECK(dns_view_load(view, stop));
5177		if (view->managed_keys != NULL)
5178			CHECK(dns_zone_load(view->managed_keys));
5179	}
5180
5181	/*
5182	 * Force zone maintenance.  Do this after loading
5183	 * so that we know when we need to force AXFR of
5184	 * slave zones whose master files are missing.
5185	 */
5186	CHECK(dns_zonemgr_forcemaint(server->zonemgr));
5187 cleanup:
5188	isc_task_endexclusive(server->task);
5189	return (result);
5190}
5191
5192static isc_result_t
5193load_new_zones(ns_server_t *server, isc_boolean_t stop) {
5194	isc_result_t result;
5195	dns_view_t *view;
5196
5197	result = isc_task_beginexclusive(server->task);
5198	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5199
5200	/*
5201	 * Load zone data from disk.
5202	 */
5203	for (view = ISC_LIST_HEAD(server->viewlist);
5204	     view != NULL;
5205	     view = ISC_LIST_NEXT(view, link))
5206	{
5207		CHECK(dns_view_loadnew(view, stop));
5208
5209		/* Load managed-keys data */
5210		if (view->managed_keys != NULL)
5211			CHECK(dns_zone_loadnew(view->managed_keys));
5212	}
5213
5214	/*
5215	 * Resume zone XFRs.
5216	 */
5217	dns_zonemgr_resumexfrs(server->zonemgr);
5218 cleanup:
5219	isc_task_endexclusive(server->task);
5220	return (result);
5221}
5222
5223static void
5224run_server(isc_task_t *task, isc_event_t *event) {
5225	isc_result_t result;
5226	ns_server_t *server = (ns_server_t *)event->ev_arg;
5227
5228	INSIST(task == server->task);
5229
5230	isc_event_free(&event);
5231
5232	CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
5233					  &ns_g_dispatchmgr),
5234		   "creating dispatch manager");
5235
5236	dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
5237
5238	CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
5239					  ns_g_socketmgr, ns_g_dispatchmgr,
5240					  &server->interfacemgr),
5241		   "creating interface manager");
5242
5243	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5244				    NULL, NULL, server->task,
5245				    interface_timer_tick,
5246				    server, &server->interface_timer),
5247		   "creating interface timer");
5248
5249	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5250				    NULL, NULL, server->task,
5251				    heartbeat_timer_tick,
5252				    server, &server->heartbeat_timer),
5253		   "creating heartbeat timer");
5254
5255	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5256				    NULL, NULL, server->task, pps_timer_tick,
5257				    server, &server->pps_timer),
5258		   "creating pps timer");
5259
5260	CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
5261		   "creating default configuration parser");
5262
5263	if (ns_g_lwresdonly)
5264		CHECKFATAL(load_configuration(lwresd_g_conffile, server,
5265					      ISC_TRUE),
5266			   "loading configuration");
5267	else
5268		CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
5269			   "loading configuration");
5270
5271	isc_hash_init();
5272
5273	CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones");
5274
5275	ns_os_started();
5276	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5277		      ISC_LOG_NOTICE, "running");
5278}
5279
5280void
5281ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
5282
5283	REQUIRE(NS_SERVER_VALID(server));
5284
5285	server->flushonshutdown = flush;
5286}
5287
5288static void
5289shutdown_server(isc_task_t *task, isc_event_t *event) {
5290	isc_result_t result;
5291	dns_view_t *view, *view_next;
5292	ns_server_t *server = (ns_server_t *)event->ev_arg;
5293	isc_boolean_t flush = server->flushonshutdown;
5294	ns_cache_t *nsc;
5295
5296	UNUSED(task);
5297	INSIST(task == server->task);
5298
5299	result = isc_task_beginexclusive(server->task);
5300	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5301
5302	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5303		      ISC_LOG_INFO, "shutting down%s",
5304		      flush ? ": flushing changes" : "");
5305
5306	ns_statschannels_shutdown(server);
5307	ns_controls_shutdown(server->controls);
5308	end_reserved_dispatches(server, ISC_TRUE);
5309	cleanup_session_key(server, server->mctx);
5310
5311	if (ns_g_aclconfctx != NULL)
5312		cfg_aclconfctx_detach(&ns_g_aclconfctx);
5313
5314	cfg_obj_destroy(ns_g_parser, &ns_g_config);
5315	cfg_parser_destroy(&ns_g_parser);
5316
5317	for (view = ISC_LIST_HEAD(server->viewlist);
5318	     view != NULL;
5319	     view = view_next) {
5320		view_next = ISC_LIST_NEXT(view, link);
5321		ISC_LIST_UNLINK(server->viewlist, view, link);
5322		if (flush)
5323			dns_view_flushanddetach(&view);
5324		else
5325			dns_view_detach(&view);
5326	}
5327
5328	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
5329		ISC_LIST_UNLINK(server->cachelist, nsc, link);
5330		dns_cache_detach(&nsc->cache);
5331		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
5332	}
5333
5334	isc_timer_detach(&server->interface_timer);
5335	isc_timer_detach(&server->heartbeat_timer);
5336	isc_timer_detach(&server->pps_timer);
5337
5338	ns_interfacemgr_shutdown(server->interfacemgr);
5339	ns_interfacemgr_detach(&server->interfacemgr);
5340
5341	dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
5342
5343	dns_zonemgr_shutdown(server->zonemgr);
5344
5345	if (ns_g_sessionkey != NULL) {
5346		dns_tsigkey_detach(&ns_g_sessionkey);
5347		dns_name_free(&ns_g_sessionkeyname, server->mctx);
5348	}
5349
5350	if (server->blackholeacl != NULL)
5351		dns_acl_detach(&server->blackholeacl);
5352
5353	dns_db_detach(&server->in_roothints);
5354
5355	isc_task_endexclusive(server->task);
5356
5357	isc_task_detach(&server->task);
5358
5359	isc_event_free(&event);
5360}
5361
5362void
5363ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
5364	isc_result_t result;
5365	ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
5366
5367	if (server == NULL)
5368		fatal("allocating server object", ISC_R_NOMEMORY);
5369
5370	server->mctx = mctx;
5371	server->task = NULL;
5372
5373	/* Initialize configuration data with default values. */
5374
5375	result = isc_quota_init(&server->xfroutquota, 10);
5376	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5377	result = isc_quota_init(&server->tcpquota, 10);
5378	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5379	result = isc_quota_init(&server->recursionquota, 100);
5380	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5381
5382	result = dns_aclenv_init(mctx, &server->aclenv);
5383	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5384
5385	/* Initialize server data structures. */
5386	server->zonemgr = NULL;
5387	server->interfacemgr = NULL;
5388	ISC_LIST_INIT(server->viewlist);
5389	server->in_roothints = NULL;
5390	server->blackholeacl = NULL;
5391
5392	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
5393				     &server->in_roothints),
5394		   "setting up root hints");
5395
5396	CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
5397		   "initializing reload event lock");
5398	server->reload_event =
5399		isc_event_allocate(ns_g_mctx, server,
5400				   NS_EVENT_RELOAD,
5401				   ns_server_reload,
5402				   server,
5403				   sizeof(isc_event_t));
5404	CHECKFATAL(server->reload_event == NULL ?
5405		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
5406		   "allocating reload event");
5407
5408	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
5409				 ns_g_engine, ISC_ENTROPY_GOODONLY),
5410		   "initializing DST");
5411
5412	server->tkeyctx = NULL;
5413	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
5414				      &server->tkeyctx),
5415		   "creating TKEY context");
5416
5417	/*
5418	 * Setup the server task, which is responsible for coordinating
5419	 * startup and shutdown of the server.
5420	 */
5421	CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
5422		   "creating server task");
5423	isc_task_setname(server->task, "server", server);
5424	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
5425		   "isc_task_onshutdown");
5426	CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
5427		   "isc_app_onrun");
5428
5429	server->interface_timer = NULL;
5430	server->heartbeat_timer = NULL;
5431	server->pps_timer = NULL;
5432
5433	server->interface_interval = 0;
5434	server->heartbeat_interval = 0;
5435
5436	CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
5437				      ns_g_socketmgr, &server->zonemgr),
5438		   "dns_zonemgr_create");
5439	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
5440		   "dns_zonemgr_setsize");
5441
5442	server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
5443	CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5444		   "isc_mem_strdup");
5445	server->nsstats = NULL;
5446	server->rcvquerystats = NULL;
5447	server->opcodestats = NULL;
5448	server->zonestats = NULL;
5449	server->resolverstats = NULL;
5450	server->sockstats = NULL;
5451	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
5452				    isc_sockstatscounter_max),
5453		   "isc_stats_create");
5454	isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
5455
5456	server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys");
5457	CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
5458						  ISC_R_SUCCESS,
5459		   "isc_mem_strdup");
5460
5461	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
5462	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5463		   "isc_mem_strdup");
5464
5465	server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
5466	CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
5467						  ISC_R_SUCCESS,
5468		   "isc_mem_strdup");
5469
5470	server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
5471	CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5472		   "isc_mem_strdup");
5473
5474	server->hostname_set = ISC_FALSE;
5475	server->hostname = NULL;
5476	server->version_set = ISC_FALSE;
5477	server->version = NULL;
5478	server->server_usehostname = ISC_FALSE;
5479	server->server_id = NULL;
5480
5481	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
5482				    dns_nsstatscounter_max),
5483		   "dns_stats_create (server)");
5484
5485	CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
5486					     &server->rcvquerystats),
5487		   "dns_stats_create (rcvquery)");
5488
5489	CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
5490		   "dns_stats_create (opcode)");
5491
5492	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
5493				    dns_zonestatscounter_max),
5494		   "dns_stats_create (zone)");
5495
5496	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
5497				    dns_resstatscounter_max),
5498		   "dns_stats_create (resolver)");
5499
5500	server->flushonshutdown = ISC_FALSE;
5501	server->log_queries = ISC_FALSE;
5502
5503	server->controls = NULL;
5504	CHECKFATAL(ns_controls_create(server, &server->controls),
5505		   "ns_controls_create");
5506	server->dispatchgen = 0;
5507	ISC_LIST_INIT(server->dispatches);
5508
5509	ISC_LIST_INIT(server->statschannels);
5510
5511	ISC_LIST_INIT(server->cachelist);
5512
5513	server->sessionkey = NULL;
5514	server->session_keyfile = NULL;
5515	server->session_keyname = NULL;
5516	server->session_keyalg = DST_ALG_UNKNOWN;
5517	server->session_keybits = 0;
5518
5519	server->magic = NS_SERVER_MAGIC;
5520	*serverp = server;
5521}
5522
5523void
5524ns_server_destroy(ns_server_t **serverp) {
5525	ns_server_t *server = *serverp;
5526	REQUIRE(NS_SERVER_VALID(server));
5527
5528	ns_controls_destroy(&server->controls);
5529
5530	isc_stats_detach(&server->nsstats);
5531	dns_stats_detach(&server->rcvquerystats);
5532	dns_stats_detach(&server->opcodestats);
5533	isc_stats_detach(&server->zonestats);
5534	isc_stats_detach(&server->resolverstats);
5535	isc_stats_detach(&server->sockstats);
5536
5537	isc_mem_free(server->mctx, server->statsfile);
5538	isc_mem_free(server->mctx, server->bindkeysfile);
5539	isc_mem_free(server->mctx, server->dumpfile);
5540	isc_mem_free(server->mctx, server->secrootsfile);
5541	isc_mem_free(server->mctx, server->recfile);
5542
5543	if (server->version != NULL)
5544		isc_mem_free(server->mctx, server->version);
5545	if (server->hostname != NULL)
5546		isc_mem_free(server->mctx, server->hostname);
5547	if (server->server_id != NULL)
5548		isc_mem_free(server->mctx, server->server_id);
5549
5550	if (server->zonemgr != NULL)
5551		dns_zonemgr_detach(&server->zonemgr);
5552
5553	if (server->tkeyctx != NULL)
5554		dns_tkeyctx_destroy(&server->tkeyctx);
5555
5556	dst_lib_destroy();
5557
5558	isc_event_free(&server->reload_event);
5559
5560	INSIST(ISC_LIST_EMPTY(server->viewlist));
5561	INSIST(ISC_LIST_EMPTY(server->cachelist));
5562
5563	dns_aclenv_destroy(&server->aclenv);
5564
5565	isc_quota_destroy(&server->recursionquota);
5566	isc_quota_destroy(&server->tcpquota);
5567	isc_quota_destroy(&server->xfroutquota);
5568
5569	server->magic = 0;
5570	isc_mem_put(server->mctx, server, sizeof(*server));
5571	*serverp = NULL;
5572}
5573
5574static void
5575fatal(const char *msg, isc_result_t result) {
5576	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5577		      ISC_LOG_CRITICAL, "%s: %s", msg,
5578		      isc_result_totext(result));
5579	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5580		      ISC_LOG_CRITICAL, "exiting (due to fatal error)");
5581	exit(1);
5582}
5583
5584static void
5585start_reserved_dispatches(ns_server_t *server) {
5586
5587	REQUIRE(NS_SERVER_VALID(server));
5588
5589	server->dispatchgen++;
5590}
5591
5592static void
5593end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
5594	ns_dispatch_t *dispatch, *nextdispatch;
5595
5596	REQUIRE(NS_SERVER_VALID(server));
5597
5598	for (dispatch = ISC_LIST_HEAD(server->dispatches);
5599	     dispatch != NULL;
5600	     dispatch = nextdispatch) {
5601		nextdispatch = ISC_LIST_NEXT(dispatch, link);
5602		if (!all && server->dispatchgen == dispatch-> dispatchgen)
5603			continue;
5604		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
5605		dns_dispatch_detach(&dispatch->dispatch);
5606		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
5607	}
5608}
5609
5610void
5611ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
5612	ns_dispatch_t *dispatch;
5613	in_port_t port;
5614	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
5615	isc_result_t result;
5616	unsigned int attrs, attrmask;
5617
5618	REQUIRE(NS_SERVER_VALID(server));
5619
5620	port = isc_sockaddr_getport(addr);
5621	if (port == 0 || port >= 1024)
5622		return;
5623
5624	for (dispatch = ISC_LIST_HEAD(server->dispatches);
5625	     dispatch != NULL;
5626	     dispatch = ISC_LIST_NEXT(dispatch, link)) {
5627		if (isc_sockaddr_equal(&dispatch->addr, addr))
5628			break;
5629	}
5630	if (dispatch != NULL) {
5631		dispatch->dispatchgen = server->dispatchgen;
5632		return;
5633	}
5634
5635	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
5636	if (dispatch == NULL) {
5637		result = ISC_R_NOMEMORY;
5638		goto cleanup;
5639	}
5640
5641	dispatch->addr = *addr;
5642	dispatch->dispatchgen = server->dispatchgen;
5643	dispatch->dispatch = NULL;
5644
5645	attrs = 0;
5646	attrs |= DNS_DISPATCHATTR_UDP;
5647	switch (isc_sockaddr_pf(addr)) {
5648	case AF_INET:
5649		attrs |= DNS_DISPATCHATTR_IPV4;
5650		break;
5651	case AF_INET6:
5652		attrs |= DNS_DISPATCHATTR_IPV6;
5653		break;
5654	default:
5655		result = ISC_R_NOTIMPLEMENTED;
5656		goto cleanup;
5657	}
5658	attrmask = 0;
5659	attrmask |= DNS_DISPATCHATTR_UDP;
5660	attrmask |= DNS_DISPATCHATTR_TCP;
5661	attrmask |= DNS_DISPATCHATTR_IPV4;
5662	attrmask |= DNS_DISPATCHATTR_IPV6;
5663
5664	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
5665				     ns_g_taskmgr, &dispatch->addr, 4096,
5666				     1000, 32768, 16411, 16433,
5667				     attrs, attrmask, &dispatch->dispatch);
5668	if (result != ISC_R_SUCCESS)
5669		goto cleanup;
5670
5671	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
5672
5673	return;
5674
5675 cleanup:
5676	if (dispatch != NULL)
5677		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
5678	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
5679	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5680		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5681		      "unable to create dispatch for reserved port %s: %s",
5682		      addrbuf, isc_result_totext(result));
5683}
5684
5685
5686static isc_result_t
5687loadconfig(ns_server_t *server) {
5688	isc_result_t result;
5689	start_reserved_dispatches(server);
5690	result = load_configuration(ns_g_lwresdonly ?
5691				    lwresd_g_conffile : ns_g_conffile,
5692				    server, ISC_FALSE);
5693	if (result == ISC_R_SUCCESS) {
5694		end_reserved_dispatches(server, ISC_FALSE);
5695		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5696			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5697			      "reloading configuration succeeded");
5698	} else {
5699		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5700			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5701			      "reloading configuration failed: %s",
5702			      isc_result_totext(result));
5703	}
5704	return (result);
5705}
5706
5707static isc_result_t
5708reload(ns_server_t *server) {
5709	isc_result_t result;
5710	CHECK(loadconfig(server));
5711
5712	result = load_zones(server, ISC_FALSE);
5713	if (result == ISC_R_SUCCESS)
5714		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5715			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5716			      "reloading zones succeeded");
5717	else
5718		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5719			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5720			      "reloading zones failed: %s",
5721			      isc_result_totext(result));
5722
5723 cleanup:
5724	return (result);
5725}
5726
5727static void
5728reconfig(ns_server_t *server) {
5729	isc_result_t result;
5730	CHECK(loadconfig(server));
5731
5732	result = load_new_zones(server, ISC_FALSE);
5733	if (result == ISC_R_SUCCESS)
5734		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5735			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5736			      "any newly configured zones are now loaded");
5737	else
5738		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5739			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5740			      "loading new zones failed: %s",
5741			      isc_result_totext(result));
5742
5743 cleanup: ;
5744}
5745
5746/*
5747 * Handle a reload event (from SIGHUP).
5748 */
5749static void
5750ns_server_reload(isc_task_t *task, isc_event_t *event) {
5751	ns_server_t *server = (ns_server_t *)event->ev_arg;
5752
5753	INSIST(task = server->task);
5754	UNUSED(task);
5755
5756	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5757		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5758		      "received SIGHUP signal to reload zones");
5759	(void)reload(server);
5760
5761	LOCK(&server->reload_event_lock);
5762	INSIST(server->reload_event == NULL);
5763	server->reload_event = event;
5764	UNLOCK(&server->reload_event_lock);
5765}
5766
5767void
5768ns_server_reloadwanted(ns_server_t *server) {
5769	LOCK(&server->reload_event_lock);
5770	if (server->reload_event != NULL)
5771		isc_task_send(server->task, &server->reload_event);
5772	UNLOCK(&server->reload_event_lock);
5773}
5774
5775static char *
5776next_token(char **stringp, const char *delim) {
5777	char *res;
5778
5779	do {
5780		res = strsep(stringp, delim);
5781		if (res == NULL)
5782			break;
5783	} while (*res == '\0');
5784	return (res);
5785}
5786
5787/*
5788 * Find the zone specified in the control channel command 'args',
5789 * if any.  If a zone is specified, point '*zonep' at it, otherwise
5790 * set '*zonep' to NULL.
5791 */
5792static isc_result_t
5793zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep,
5794	       const char **zonename)
5795{
5796	char *input, *ptr;
5797	const char *zonetxt;
5798	char *classtxt;
5799	const char *viewtxt = NULL;
5800	dns_fixedname_t name;
5801	isc_result_t result;
5802	isc_buffer_t buf;
5803	dns_view_t *view = NULL;
5804	dns_rdataclass_t rdclass;
5805
5806	REQUIRE(zonep != NULL && *zonep == NULL);
5807
5808	input = args;
5809
5810	/* Skip the command name. */
5811	ptr = next_token(&input, " \t");
5812	if (ptr == NULL)
5813		return (ISC_R_UNEXPECTEDEND);
5814
5815	/* Look for the zone name. */
5816	zonetxt = next_token(&input, " \t");
5817	if (zonetxt == NULL)
5818		return (ISC_R_SUCCESS);
5819	if (zonename)
5820		*zonename = zonetxt;
5821
5822	/* Look for the optional class name. */
5823	classtxt = next_token(&input, " \t");
5824	if (classtxt != NULL) {
5825		/* Look for the optional view name. */
5826		viewtxt = next_token(&input, " \t");
5827	}
5828
5829	isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
5830	isc_buffer_add(&buf, strlen(zonetxt));
5831	dns_fixedname_init(&name);
5832	result = dns_name_fromtext(dns_fixedname_name(&name),
5833				   &buf, dns_rootname, 0, NULL);
5834	if (result != ISC_R_SUCCESS)
5835		goto fail1;
5836
5837	if (classtxt != NULL) {
5838		isc_textregion_t r;
5839		r.base = classtxt;
5840		r.length = strlen(classtxt);
5841		result = dns_rdataclass_fromtext(&rdclass, &r);
5842		if (result != ISC_R_SUCCESS)
5843			goto fail1;
5844	} else
5845		rdclass = dns_rdataclass_in;
5846
5847	if (viewtxt == NULL) {
5848		result = dns_viewlist_findzone(&server->viewlist,
5849					       dns_fixedname_name(&name),
5850					       ISC_TF(classtxt == NULL),
5851					       rdclass, zonep);
5852	} else {
5853		result = dns_viewlist_find(&server->viewlist, viewtxt,
5854					   rdclass, &view);
5855		if (result != ISC_R_SUCCESS)
5856			goto fail1;
5857
5858		result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
5859				     0, NULL, zonep);
5860		dns_view_detach(&view);
5861	}
5862
5863	/* Partial match? */
5864	if (result != ISC_R_SUCCESS && *zonep != NULL)
5865		dns_zone_detach(zonep);
5866	if (result == DNS_R_PARTIALMATCH)
5867		result = ISC_R_NOTFOUND;
5868 fail1:
5869	return (result);
5870}
5871
5872/*
5873 * Act on a "retransfer" command from the command channel.
5874 */
5875isc_result_t
5876ns_server_retransfercommand(ns_server_t *server, char *args) {
5877	isc_result_t result;
5878	dns_zone_t *zone = NULL;
5879	dns_zonetype_t type;
5880
5881	result = zone_from_args(server, args, &zone, NULL);
5882	if (result != ISC_R_SUCCESS)
5883		return (result);
5884	if (zone == NULL)
5885		return (ISC_R_UNEXPECTEDEND);
5886	type = dns_zone_gettype(zone);
5887	if (type == dns_zone_slave || type == dns_zone_stub)
5888		dns_zone_forcereload(zone);
5889	else
5890		result = ISC_R_NOTFOUND;
5891	dns_zone_detach(&zone);
5892	return (result);
5893}
5894
5895/*
5896 * Act on a "reload" command from the command channel.
5897 */
5898isc_result_t
5899ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
5900	isc_result_t result;
5901	dns_zone_t *zone = NULL;
5902	dns_zonetype_t type;
5903	const char *msg = NULL;
5904
5905	result = zone_from_args(server, args, &zone, NULL);
5906	if (result != ISC_R_SUCCESS)
5907		return (result);
5908	if (zone == NULL) {
5909		result = reload(server);
5910		if (result == ISC_R_SUCCESS)
5911			msg = "server reload successful";
5912	} else {
5913		type = dns_zone_gettype(zone);
5914		if (type == dns_zone_slave || type == dns_zone_stub) {
5915			dns_zone_refresh(zone);
5916			dns_zone_detach(&zone);
5917			msg = "zone refresh queued";
5918		} else {
5919			result = dns_zone_load(zone);
5920			dns_zone_detach(&zone);
5921			switch (result) {
5922			case ISC_R_SUCCESS:
5923				 msg = "zone reload successful";
5924				 break;
5925			case DNS_R_CONTINUE:
5926				msg = "zone reload queued";
5927				result = ISC_R_SUCCESS;
5928				break;
5929			case DNS_R_UPTODATE:
5930				msg = "zone reload up-to-date";
5931				result = ISC_R_SUCCESS;
5932				break;
5933			default:
5934				/* failure message will be generated by rndc */
5935				break;
5936			}
5937		}
5938	}
5939	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
5940		isc_buffer_putmem(text, (const unsigned char *)msg,
5941				  strlen(msg) + 1);
5942	return (result);
5943}
5944
5945/*
5946 * Act on a "reconfig" command from the command channel.
5947 */
5948isc_result_t
5949ns_server_reconfigcommand(ns_server_t *server, char *args) {
5950	UNUSED(args);
5951
5952	reconfig(server);
5953	return (ISC_R_SUCCESS);
5954}
5955
5956/*
5957 * Act on a "notify" command from the command channel.
5958 */
5959isc_result_t
5960ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
5961	isc_result_t result;
5962	dns_zone_t *zone = NULL;
5963	const unsigned char msg[] = "zone notify queued";
5964
5965	result = zone_from_args(server, args, &zone, NULL);
5966	if (result != ISC_R_SUCCESS)
5967		return (result);
5968	if (zone == NULL)
5969		return (ISC_R_UNEXPECTEDEND);
5970
5971	dns_zone_notify(zone);
5972	dns_zone_detach(&zone);
5973	if (sizeof(msg) <= isc_buffer_availablelength(text))
5974		isc_buffer_putmem(text, msg, sizeof(msg));
5975
5976	return (ISC_R_SUCCESS);
5977}
5978
5979/*
5980 * Act on a "refresh" command from the command channel.
5981 */
5982isc_result_t
5983ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
5984	isc_result_t result;
5985	dns_zone_t *zone = NULL;
5986	const unsigned char msg1[] = "zone refresh queued";
5987	const unsigned char msg2[] = "not a slave or stub zone";
5988	dns_zonetype_t type;
5989
5990	result = zone_from_args(server, args, &zone, NULL);
5991	if (result != ISC_R_SUCCESS)
5992		return (result);
5993	if (zone == NULL)
5994		return (ISC_R_UNEXPECTEDEND);
5995
5996	type = dns_zone_gettype(zone);
5997	if (type == dns_zone_slave || type == dns_zone_stub) {
5998		dns_zone_refresh(zone);
5999		dns_zone_detach(&zone);
6000		if (sizeof(msg1) <= isc_buffer_availablelength(text))
6001			isc_buffer_putmem(text, msg1, sizeof(msg1));
6002		return (ISC_R_SUCCESS);
6003	}
6004
6005	dns_zone_detach(&zone);
6006	if (sizeof(msg2) <= isc_buffer_availablelength(text))
6007		isc_buffer_putmem(text, msg2, sizeof(msg2));
6008	return (ISC_R_FAILURE);
6009}
6010
6011isc_result_t
6012ns_server_togglequerylog(ns_server_t *server) {
6013	server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
6014
6015	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6016		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6017		      "query logging is now %s",
6018		      server->log_queries ? "on" : "off");
6019	return (ISC_R_SUCCESS);
6020}
6021
6022static isc_result_t
6023ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
6024			 cfg_aclconfctx_t *actx,
6025			 isc_mem_t *mctx, ns_listenlist_t **target)
6026{
6027	isc_result_t result;
6028	const cfg_listelt_t *element;
6029	ns_listenlist_t *dlist = NULL;
6030
6031	REQUIRE(target != NULL && *target == NULL);
6032
6033	result = ns_listenlist_create(mctx, &dlist);
6034	if (result != ISC_R_SUCCESS)
6035		return (result);
6036
6037	for (element = cfg_list_first(listenlist);
6038	     element != NULL;
6039	     element = cfg_list_next(element))
6040	{
6041		ns_listenelt_t *delt = NULL;
6042		const cfg_obj_t *listener = cfg_listelt_value(element);
6043		result = ns_listenelt_fromconfig(listener, config, actx,
6044						 mctx, &delt);
6045		if (result != ISC_R_SUCCESS)
6046			goto cleanup;
6047		ISC_LIST_APPEND(dlist->elts, delt, link);
6048	}
6049	*target = dlist;
6050	return (ISC_R_SUCCESS);
6051
6052 cleanup:
6053	ns_listenlist_detach(&dlist);
6054	return (result);
6055}
6056
6057/*
6058 * Create a listen list from the corresponding configuration
6059 * data structure.
6060 */
6061static isc_result_t
6062ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
6063			cfg_aclconfctx_t *actx,
6064			isc_mem_t *mctx, ns_listenelt_t **target)
6065{
6066	isc_result_t result;
6067	const cfg_obj_t *portobj;
6068	in_port_t port;
6069	ns_listenelt_t *delt = NULL;
6070	REQUIRE(target != NULL && *target == NULL);
6071
6072	portobj = cfg_tuple_get(listener, "port");
6073	if (!cfg_obj_isuint32(portobj)) {
6074		if (ns_g_port != 0) {
6075			port = ns_g_port;
6076		} else {
6077			result = ns_config_getport(config, &port);
6078			if (result != ISC_R_SUCCESS)
6079				return (result);
6080		}
6081	} else {
6082		if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
6083			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
6084				    "port value '%u' is out of range",
6085				    cfg_obj_asuint32(portobj));
6086			return (ISC_R_RANGE);
6087		}
6088		port = (in_port_t)cfg_obj_asuint32(portobj);
6089	}
6090
6091	result = ns_listenelt_create(mctx, port, NULL, &delt);
6092	if (result != ISC_R_SUCCESS)
6093		return (result);
6094
6095	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
6096				   config, ns_g_lctx, actx, mctx, 0,
6097				   &delt->acl);
6098	if (result != ISC_R_SUCCESS) {
6099		ns_listenelt_destroy(delt);
6100		return (result);
6101	}
6102	*target = delt;
6103	return (ISC_R_SUCCESS);
6104}
6105
6106isc_result_t
6107ns_server_dumpstats(ns_server_t *server) {
6108	isc_result_t result;
6109	FILE *fp = NULL;
6110
6111	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
6112		"could not open statistics dump file", server->statsfile);
6113
6114	result = ns_stats_dump(server, fp);
6115
6116 cleanup:
6117	if (fp != NULL)
6118		(void)isc_stdio_close(fp);
6119	if (result == ISC_R_SUCCESS)
6120		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6121			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6122			      "dumpstats complete");
6123	else
6124		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6125			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6126			      "dumpstats failed: %s",
6127			      dns_result_totext(result));
6128	return (result);
6129}
6130
6131static isc_result_t
6132add_zone_tolist(dns_zone_t *zone, void *uap) {
6133	struct dumpcontext *dctx = uap;
6134	struct zonelistentry *zle;
6135
6136	zle = isc_mem_get(dctx->mctx, sizeof *zle);
6137	if (zle ==  NULL)
6138		return (ISC_R_NOMEMORY);
6139	zle->zone = NULL;
6140	dns_zone_attach(zone, &zle->zone);
6141	ISC_LINK_INIT(zle, link);
6142	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
6143	return (ISC_R_SUCCESS);
6144}
6145
6146static isc_result_t
6147add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
6148	struct viewlistentry *vle;
6149	isc_result_t result = ISC_R_SUCCESS;
6150
6151	/*
6152	 * Prevent duplicate views.
6153	 */
6154	for (vle = ISC_LIST_HEAD(dctx->viewlist);
6155	     vle != NULL;
6156	     vle = ISC_LIST_NEXT(vle, link))
6157		if (vle->view == view)
6158			return (ISC_R_SUCCESS);
6159
6160	vle = isc_mem_get(dctx->mctx, sizeof *vle);
6161	if (vle == NULL)
6162		return (ISC_R_NOMEMORY);
6163	vle->view = NULL;
6164	dns_view_attach(view, &vle->view);
6165	ISC_LINK_INIT(vle, link);
6166	ISC_LIST_INIT(vle->zonelist);
6167	ISC_LIST_APPEND(dctx->viewlist, vle, link);
6168	if (dctx->dumpzones)
6169		result = dns_zt_apply(view->zonetable, ISC_TRUE,
6170				      add_zone_tolist, dctx);
6171	return (result);
6172}
6173
6174static void
6175dumpcontext_destroy(struct dumpcontext *dctx) {
6176	struct viewlistentry *vle;
6177	struct zonelistentry *zle;
6178
6179	vle = ISC_LIST_HEAD(dctx->viewlist);
6180	while (vle != NULL) {
6181		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
6182		zle = ISC_LIST_HEAD(vle->zonelist);
6183		while (zle != NULL) {
6184			ISC_LIST_UNLINK(vle->zonelist, zle, link);
6185			dns_zone_detach(&zle->zone);
6186			isc_mem_put(dctx->mctx, zle, sizeof *zle);
6187			zle = ISC_LIST_HEAD(vle->zonelist);
6188		}
6189		dns_view_detach(&vle->view);
6190		isc_mem_put(dctx->mctx, vle, sizeof *vle);
6191		vle = ISC_LIST_HEAD(dctx->viewlist);
6192	}
6193	if (dctx->version != NULL)
6194		dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
6195	if (dctx->db != NULL)
6196		dns_db_detach(&dctx->db);
6197	if (dctx->cache != NULL)
6198		dns_db_detach(&dctx->cache);
6199	if (dctx->task != NULL)
6200		isc_task_detach(&dctx->task);
6201	if (dctx->fp != NULL)
6202		(void)isc_stdio_close(dctx->fp);
6203	if (dctx->mdctx != NULL)
6204		dns_dumpctx_detach(&dctx->mdctx);
6205	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
6206}
6207
6208static void
6209dumpdone(void *arg, isc_result_t result) {
6210	struct dumpcontext *dctx = arg;
6211	char buf[1024+32];
6212	const dns_master_style_t *style;
6213
6214	if (result != ISC_R_SUCCESS)
6215		goto cleanup;
6216	if (dctx->mdctx != NULL)
6217		dns_dumpctx_detach(&dctx->mdctx);
6218	if (dctx->view == NULL) {
6219		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
6220		if (dctx->view == NULL)
6221			goto done;
6222		INSIST(dctx->zone == NULL);
6223	} else
6224		goto resume;
6225 nextview:
6226	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
6227 resume:
6228	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
6229		fprintf(dctx->fp,
6230			";\n; Cache of view '%s' is shared as '%s'\n",
6231			dctx->view->view->name,
6232			dns_cache_getname(dctx->view->view->cache));
6233	} else if (dctx->zone == NULL && dctx->cache == NULL &&
6234		   dctx->dumpcache)
6235	{
6236		style = &dns_master_style_cache;
6237		/* start cache dump */
6238		if (dctx->view->view->cachedb != NULL)
6239			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
6240		if (dctx->cache != NULL) {
6241			fprintf(dctx->fp,
6242				";\n; Cache dump of view '%s' (cache %s)\n;\n",
6243				dctx->view->view->name,
6244				dns_cache_getname(dctx->view->view->cache));
6245			result = dns_master_dumptostreaminc(dctx->mctx,
6246							    dctx->cache, NULL,
6247							    style, dctx->fp,
6248							    dctx->task,
6249							    dumpdone, dctx,
6250							    &dctx->mdctx);
6251			if (result == DNS_R_CONTINUE)
6252				return;
6253			if (result == ISC_R_NOTIMPLEMENTED)
6254				fprintf(dctx->fp, "; %s\n",
6255					dns_result_totext(result));
6256			else if (result != ISC_R_SUCCESS)
6257				goto cleanup;
6258		}
6259	}
6260	if (dctx->cache != NULL) {
6261		dns_adb_dump(dctx->view->view->adb, dctx->fp);
6262		dns_resolver_printbadcache(dctx->view->view->resolver,
6263					   dctx->fp);
6264		dns_db_detach(&dctx->cache);
6265	}
6266	if (dctx->dumpzones) {
6267		style = &dns_master_style_full;
6268 nextzone:
6269		if (dctx->version != NULL)
6270			dns_db_closeversion(dctx->db, &dctx->version,
6271					    ISC_FALSE);
6272		if (dctx->db != NULL)
6273			dns_db_detach(&dctx->db);
6274		if (dctx->zone == NULL)
6275			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
6276		else
6277			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
6278		if (dctx->zone != NULL) {
6279			/* start zone dump */
6280			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
6281			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
6282			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
6283			if (result != ISC_R_SUCCESS) {
6284				fprintf(dctx->fp, "; %s\n",
6285					dns_result_totext(result));
6286				goto nextzone;
6287			}
6288			dns_db_currentversion(dctx->db, &dctx->version);
6289			result = dns_master_dumptostreaminc(dctx->mctx,
6290							    dctx->db,
6291							    dctx->version,
6292							    style, dctx->fp,
6293							    dctx->task,
6294							    dumpdone, dctx,
6295							    &dctx->mdctx);
6296			if (result == DNS_R_CONTINUE)
6297				return;
6298			if (result == ISC_R_NOTIMPLEMENTED) {
6299				fprintf(dctx->fp, "; %s\n",
6300					dns_result_totext(result));
6301				result = ISC_R_SUCCESS;
6302				POST(result);
6303				goto nextzone;
6304			}
6305			if (result != ISC_R_SUCCESS)
6306				goto cleanup;
6307		}
6308	}
6309	if (dctx->view != NULL)
6310		dctx->view = ISC_LIST_NEXT(dctx->view, link);
6311	if (dctx->view != NULL)
6312		goto nextview;
6313 done:
6314	fprintf(dctx->fp, "; Dump complete\n");
6315	result = isc_stdio_flush(dctx->fp);
6316	if (result == ISC_R_SUCCESS)
6317		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6318			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6319			      "dumpdb complete");
6320 cleanup:
6321	if (result != ISC_R_SUCCESS)
6322		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6323			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6324			      "dumpdb failed: %s", dns_result_totext(result));
6325	dumpcontext_destroy(dctx);
6326}
6327
6328isc_result_t
6329ns_server_dumpdb(ns_server_t *server, char *args) {
6330	struct dumpcontext *dctx = NULL;
6331	dns_view_t *view;
6332	isc_result_t result;
6333	char *ptr;
6334	const char *sep;
6335
6336	/* Skip the command name. */
6337	ptr = next_token(&args, " \t");
6338	if (ptr == NULL)
6339		return (ISC_R_UNEXPECTEDEND);
6340
6341	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
6342	if (dctx == NULL)
6343		return (ISC_R_NOMEMORY);
6344
6345	dctx->mctx = server->mctx;
6346	dctx->dumpcache = ISC_TRUE;
6347	dctx->dumpzones = ISC_FALSE;
6348	dctx->fp = NULL;
6349	ISC_LIST_INIT(dctx->viewlist);
6350	dctx->view = NULL;
6351	dctx->zone = NULL;
6352	dctx->cache = NULL;
6353	dctx->mdctx = NULL;
6354	dctx->db = NULL;
6355	dctx->cache = NULL;
6356	dctx->task = NULL;
6357	dctx->version = NULL;
6358	isc_task_attach(server->task, &dctx->task);
6359
6360	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
6361		"could not open dump file", server->dumpfile);
6362
6363	sep = (args == NULL) ? "" : ": ";
6364	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6365		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6366		      "dumpdb started%s%s", sep, (args != NULL) ? args : "");
6367
6368	ptr = next_token(&args, " \t");
6369	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
6370		dctx->dumpzones = ISC_TRUE;
6371		dctx->dumpcache = ISC_TRUE;
6372		ptr = next_token(&args, " \t");
6373	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
6374		dctx->dumpzones = ISC_FALSE;
6375		dctx->dumpcache = ISC_TRUE;
6376		ptr = next_token(&args, " \t");
6377	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
6378		dctx->dumpzones = ISC_TRUE;
6379		dctx->dumpcache = ISC_FALSE;
6380		ptr = next_token(&args, " \t");
6381	}
6382
6383 nextview:
6384	for (view = ISC_LIST_HEAD(server->viewlist);
6385	     view != NULL;
6386	     view = ISC_LIST_NEXT(view, link))
6387	{
6388		if (ptr != NULL && strcmp(view->name, ptr) != 0)
6389			continue;
6390		CHECK(add_view_tolist(dctx, view));
6391	}
6392	if (ptr != NULL) {
6393		ptr = next_token(&args, " \t");
6394		if (ptr != NULL)
6395			goto nextview;
6396	}
6397	dumpdone(dctx, ISC_R_SUCCESS);
6398	return (ISC_R_SUCCESS);
6399
6400 cleanup:
6401	if (dctx != NULL)
6402		dumpcontext_destroy(dctx);
6403	return (result);
6404}
6405
6406isc_result_t
6407ns_server_dumpsecroots(ns_server_t *server, char *args) {
6408	dns_view_t *view;
6409	dns_keytable_t *secroots = NULL;
6410	isc_result_t result;
6411	char *ptr;
6412	FILE *fp = NULL;
6413	isc_time_t now;
6414	char tbuf[64];
6415
6416	/* Skip the command name. */
6417	ptr = next_token(&args, " \t");
6418	if (ptr == NULL)
6419		return (ISC_R_UNEXPECTEDEND);
6420	ptr = next_token(&args, " \t");
6421
6422	CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp),
6423		"could not open secroots dump file", server->secrootsfile);
6424	TIME_NOW(&now);
6425	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
6426	fprintf(fp, "%s\n", tbuf);
6427
6428	do {
6429		for (view = ISC_LIST_HEAD(server->viewlist);
6430		     view != NULL;
6431		     view = ISC_LIST_NEXT(view, link))
6432		{
6433			if (ptr != NULL && strcmp(view->name, ptr) != 0)
6434				continue;
6435			if (secroots != NULL)
6436				dns_keytable_detach(&secroots);
6437			result = dns_view_getsecroots(view, &secroots);
6438			if (result == ISC_R_NOTFOUND) {
6439				result = ISC_R_SUCCESS;
6440				continue;
6441			}
6442			fprintf(fp, "\n Start view %s\n\n", view->name);
6443			result = dns_keytable_dump(secroots, fp);
6444			if (result != ISC_R_SUCCESS)
6445				fprintf(fp, " dumpsecroots failed: %s\n",
6446					isc_result_totext(result));
6447		}
6448		if (ptr != NULL)
6449			ptr = next_token(&args, " \t");
6450	} while (ptr != NULL);
6451
6452 cleanup:
6453	if (secroots != NULL)
6454		dns_keytable_detach(&secroots);
6455	if (fp != NULL)
6456		(void)isc_stdio_close(fp);
6457	if (result == ISC_R_SUCCESS)
6458		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6459			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6460			      "dumpsecroots complete");
6461	else
6462		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6463			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6464			      "dumpsecroots failed: %s",
6465			      dns_result_totext(result));
6466	return (result);
6467}
6468
6469isc_result_t
6470ns_server_dumprecursing(ns_server_t *server) {
6471	FILE *fp = NULL;
6472	isc_result_t result;
6473
6474	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
6475		"could not open dump file", server->recfile);
6476	fprintf(fp,";\n; Recursing Queries\n;\n");
6477	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
6478	fprintf(fp, "; Dump complete\n");
6479
6480 cleanup:
6481	if (fp != NULL)
6482		result = isc_stdio_close(fp);
6483	if (result == ISC_R_SUCCESS)
6484		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6485			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6486			      "dumprecursing complete");
6487	else
6488		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6489			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6490			      "dumprecursing failed: %s",
6491			      dns_result_totext(result));
6492	return (result);
6493}
6494
6495isc_result_t
6496ns_server_setdebuglevel(ns_server_t *server, char *args) {
6497	char *ptr;
6498	char *levelstr;
6499	char *endp;
6500	long newlevel;
6501
6502	UNUSED(server);
6503
6504	/* Skip the command name. */
6505	ptr = next_token(&args, " \t");
6506	if (ptr == NULL)
6507		return (ISC_R_UNEXPECTEDEND);
6508
6509	/* Look for the new level name. */
6510	levelstr = next_token(&args, " \t");
6511	if (levelstr == NULL) {
6512		if (ns_g_debuglevel < 99)
6513			ns_g_debuglevel++;
6514	} else {
6515		newlevel = strtol(levelstr, &endp, 10);
6516		if (*endp != '\0' || newlevel < 0 || newlevel > 99)
6517			return (ISC_R_RANGE);
6518		ns_g_debuglevel = (unsigned int)newlevel;
6519	}
6520	isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
6521	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6522		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6523		      "debug level is now %d", ns_g_debuglevel);
6524	return (ISC_R_SUCCESS);
6525}
6526
6527isc_result_t
6528ns_server_validation(ns_server_t *server, char *args) {
6529	char *ptr, *viewname;
6530	dns_view_t *view;
6531	isc_boolean_t changed = ISC_FALSE;
6532	isc_result_t result;
6533	isc_boolean_t enable;
6534
6535	/* Skip the command name. */
6536	ptr = next_token(&args, " \t");
6537	if (ptr == NULL)
6538		return (ISC_R_UNEXPECTEDEND);
6539
6540	/* Find out what we are to do. */
6541	ptr = next_token(&args, " \t");
6542	if (ptr == NULL)
6543		return (ISC_R_UNEXPECTEDEND);
6544
6545	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
6546	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
6547		enable = ISC_TRUE;
6548	else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
6549		 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
6550		enable = ISC_FALSE;
6551	else
6552		return (DNS_R_SYNTAX);
6553
6554	/* Look for the view name. */
6555	viewname = next_token(&args, " \t");
6556
6557	result = isc_task_beginexclusive(server->task);
6558	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6559	for (view = ISC_LIST_HEAD(server->viewlist);
6560	     view != NULL;
6561	     view = ISC_LIST_NEXT(view, link))
6562	{
6563		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
6564			continue;
6565		result = dns_view_flushcache(view);
6566		if (result != ISC_R_SUCCESS)
6567			goto out;
6568		view->enablevalidation = enable;
6569		changed = ISC_TRUE;
6570	}
6571	if (changed)
6572		result = ISC_R_SUCCESS;
6573	else
6574		result = ISC_R_FAILURE;
6575 out:
6576	isc_task_endexclusive(server->task);
6577	return (result);
6578}
6579
6580isc_result_t
6581ns_server_flushcache(ns_server_t *server, char *args) {
6582	char *ptr, *viewname;
6583	dns_view_t *view;
6584	isc_boolean_t flushed;
6585	isc_boolean_t found;
6586	isc_result_t result;
6587	ns_cache_t *nsc;
6588
6589	/* Skip the command name. */
6590	ptr = next_token(&args, " \t");
6591	if (ptr == NULL)
6592		return (ISC_R_UNEXPECTEDEND);
6593
6594	/* Look for the view name. */
6595	viewname = next_token(&args, " \t");
6596
6597	result = isc_task_beginexclusive(server->task);
6598	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6599	flushed = ISC_TRUE;
6600	found = ISC_FALSE;
6601
6602	/*
6603	 * Flushing a cache is tricky when caches are shared by multiple views.
6604	 * We first identify which caches should be flushed in the local cache
6605	 * list, flush these caches, and then update other views that refer to
6606	 * the flushed cache DB.
6607	 */
6608	if (viewname != NULL) {
6609		/*
6610		 * Mark caches that need to be flushed.  This is an O(#view^2)
6611		 * operation in the very worst case, but should be normally
6612		 * much more lightweight because only a few (most typically just
6613		 * one) views will match.
6614		 */
6615		for (view = ISC_LIST_HEAD(server->viewlist);
6616		     view != NULL;
6617		     view = ISC_LIST_NEXT(view, link))
6618		{
6619			if (strcasecmp(viewname, view->name) != 0)
6620				continue;
6621			found = ISC_TRUE;
6622			for (nsc = ISC_LIST_HEAD(server->cachelist);
6623			     nsc != NULL;
6624			     nsc = ISC_LIST_NEXT(nsc, link)) {
6625				if (nsc->cache == view->cache)
6626					break;
6627			}
6628			INSIST(nsc != NULL);
6629			nsc->needflush = ISC_TRUE;
6630		}
6631	} else
6632		found = ISC_TRUE;
6633
6634	/* Perform flush */
6635	for (nsc = ISC_LIST_HEAD(server->cachelist);
6636	     nsc != NULL;
6637	     nsc = ISC_LIST_NEXT(nsc, link)) {
6638		if (viewname != NULL && !nsc->needflush)
6639			continue;
6640		nsc->needflush = ISC_TRUE;
6641		result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
6642		if (result != ISC_R_SUCCESS) {
6643			flushed = ISC_FALSE;
6644			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6645				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6646				      "flushing cache in view '%s' failed: %s",
6647				      nsc->primaryview->name,
6648				      isc_result_totext(result));
6649		}
6650	}
6651
6652	/*
6653	 * Fix up views that share a flushed cache: let the views update the
6654	 * cache DB they're referring to.  This could also be an expensive
6655	 * operation, but should typically be marginal: the inner loop is only
6656	 * necessary for views that share a cache, and if there are many such
6657	 * views the number of shared cache should normally be small.
6658	 * A worst case is that we have n views and n/2 caches, each shared by
6659	 * two views.  Then this will be a O(n^2/4) operation.
6660	 */
6661	for (view = ISC_LIST_HEAD(server->viewlist);
6662	     view != NULL;
6663	     view = ISC_LIST_NEXT(view, link))
6664	{
6665		if (!dns_view_iscacheshared(view))
6666			continue;
6667		for (nsc = ISC_LIST_HEAD(server->cachelist);
6668		     nsc != NULL;
6669		     nsc = ISC_LIST_NEXT(nsc, link)) {
6670			if (!nsc->needflush || nsc->cache != view->cache)
6671				continue;
6672			result = dns_view_flushcache2(view, ISC_TRUE);
6673			if (result != ISC_R_SUCCESS) {
6674				flushed = ISC_FALSE;
6675				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6676					      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6677					      "fixing cache in view '%s' "
6678					      "failed: %s", view->name,
6679					      isc_result_totext(result));
6680			}
6681		}
6682	}
6683
6684	/* Cleanup the cache list. */
6685	for (nsc = ISC_LIST_HEAD(server->cachelist);
6686	     nsc != NULL;
6687	     nsc = ISC_LIST_NEXT(nsc, link)) {
6688		nsc->needflush = ISC_FALSE;
6689	}
6690
6691	if (flushed && found) {
6692		if (viewname != NULL)
6693			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6694				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6695				      "flushing cache in view '%s' succeeded",
6696				      viewname);
6697		else
6698			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6699				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6700				      "flushing caches in all views succeeded");
6701		result = ISC_R_SUCCESS;
6702	} else {
6703		if (!found) {
6704			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6705				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6706				      "flushing cache in view '%s' failed: "
6707				      "view not found", viewname);
6708			result = ISC_R_NOTFOUND;
6709		} else
6710			result = ISC_R_FAILURE;
6711	}
6712	isc_task_endexclusive(server->task);
6713	return (result);
6714}
6715
6716isc_result_t
6717ns_server_flushname(ns_server_t *server, char *args) {
6718	char *ptr, *target, *viewname;
6719	dns_view_t *view;
6720	isc_boolean_t flushed;
6721	isc_boolean_t found;
6722	isc_result_t result;
6723	isc_buffer_t b;
6724	dns_fixedname_t fixed;
6725	dns_name_t *name;
6726
6727	/* Skip the command name. */
6728	ptr = next_token(&args, " \t");
6729	if (ptr == NULL)
6730		return (ISC_R_UNEXPECTEDEND);
6731
6732	/* Find the domain name to flush. */
6733	target = next_token(&args, " \t");
6734	if (target == NULL)
6735		return (ISC_R_UNEXPECTEDEND);
6736
6737	isc_buffer_init(&b, target, strlen(target));
6738	isc_buffer_add(&b, strlen(target));
6739	dns_fixedname_init(&fixed);
6740	name = dns_fixedname_name(&fixed);
6741	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
6742	if (result != ISC_R_SUCCESS)
6743		return (result);
6744
6745	/* Look for the view name. */
6746	viewname = next_token(&args, " \t");
6747
6748	result = isc_task_beginexclusive(server->task);
6749	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6750	flushed = ISC_TRUE;
6751	found = ISC_FALSE;
6752	for (view = ISC_LIST_HEAD(server->viewlist);
6753	     view != NULL;
6754	     view = ISC_LIST_NEXT(view, link))
6755	{
6756		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
6757			continue;
6758		found = ISC_TRUE;
6759		/*
6760		 * It's a little inefficient to try flushing name for all views
6761		 * if some of the views share a single cache.  But since the
6762		 * operation is lightweight we prefer simplicity here.
6763		 */
6764		result = dns_view_flushname(view, name);
6765		if (result != ISC_R_SUCCESS) {
6766			flushed = ISC_FALSE;
6767			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6768				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6769				      "flushing name '%s' in cache view '%s' "
6770				      "failed: %s", target, view->name,
6771				      isc_result_totext(result));
6772		}
6773	}
6774	if (flushed && found) {
6775		if (viewname != NULL)
6776			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6777				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6778				      "flushing name '%s' in cache view '%s' "
6779				      "succeeded", target, viewname);
6780		else
6781			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6782				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6783				      "flushing name '%s' in all cache views "
6784				      "succeeded", target);
6785		result = ISC_R_SUCCESS;
6786	} else {
6787		if (!found)
6788			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6789				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6790				      "flushing name '%s' in cache view '%s' "
6791				      "failed: view not found", target,
6792				      viewname);
6793		result = ISC_R_FAILURE;
6794	}
6795	isc_task_endexclusive(server->task);
6796	return (result);
6797}
6798
6799isc_result_t
6800ns_server_status(ns_server_t *server, isc_buffer_t *text) {
6801	int zonecount, xferrunning, xferdeferred, soaqueries;
6802	unsigned int n;
6803	const char *ob = "", *cb = "", *alt = "";
6804
6805	if (ns_g_server->version_set) {
6806		ob = " (";
6807		cb = ")";
6808		if (ns_g_server->version == NULL)
6809			alt = "version.bind/txt/ch disabled";
6810		else
6811			alt = ns_g_server->version;
6812	}
6813	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
6814	xferrunning = dns_zonemgr_getcount(server->zonemgr,
6815					   DNS_ZONESTATE_XFERRUNNING);
6816	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
6817					    DNS_ZONESTATE_XFERDEFERRED);
6818	soaqueries = dns_zonemgr_getcount(server->zonemgr,
6819					  DNS_ZONESTATE_SOAQUERY);
6820
6821	n = snprintf((char *)isc_buffer_used(text),
6822		     isc_buffer_availablelength(text),
6823		     "version: %s%s%s%s\n"
6824#ifdef ISC_PLATFORM_USETHREADS
6825		     "CPUs found: %u\n"
6826		     "worker threads: %u\n"
6827#endif
6828		     "number of zones: %u\n"
6829		     "debug level: %d\n"
6830		     "xfers running: %u\n"
6831		     "xfers deferred: %u\n"
6832		     "soa queries in progress: %u\n"
6833		     "query logging is %s\n"
6834		     "recursive clients: %d/%d/%d\n"
6835		     "tcp clients: %d/%d\n"
6836		     "server is up and running",
6837		     ns_g_version, ob, alt, cb,
6838#ifdef ISC_PLATFORM_USETHREADS
6839		     ns_g_cpus_detected, ns_g_cpus,
6840#endif
6841		     zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
6842		     soaqueries, server->log_queries ? "ON" : "OFF",
6843		     server->recursionquota.used, server->recursionquota.soft,
6844		     server->recursionquota.max,
6845		     server->tcpquota.used, server->tcpquota.max);
6846	if (n >= isc_buffer_availablelength(text))
6847		return (ISC_R_NOSPACE);
6848	isc_buffer_add(text, n);
6849	return (ISC_R_SUCCESS);
6850}
6851
6852static isc_result_t
6853delete_keynames(dns_tsig_keyring_t *ring, char *target,
6854		unsigned int *foundkeys)
6855{
6856	char namestr[DNS_NAME_FORMATSIZE];
6857	isc_result_t result;
6858	dns_rbtnodechain_t chain;
6859	dns_name_t foundname;
6860	dns_fixedname_t fixedorigin;
6861	dns_name_t *origin;
6862	dns_rbtnode_t *node;
6863	dns_tsigkey_t *tkey;
6864
6865	dns_name_init(&foundname, NULL);
6866	dns_fixedname_init(&fixedorigin);
6867	origin = dns_fixedname_name(&fixedorigin);
6868
6869 again:
6870	dns_rbtnodechain_init(&chain, ring->mctx);
6871	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
6872					origin);
6873	if (result == ISC_R_NOTFOUND) {
6874		dns_rbtnodechain_invalidate(&chain);
6875		return (ISC_R_SUCCESS);
6876	}
6877	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6878		dns_rbtnodechain_invalidate(&chain);
6879		return (result);
6880	}
6881
6882	for (;;) {
6883		node = NULL;
6884		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
6885		tkey = node->data;
6886
6887		if (tkey != NULL) {
6888			if (!tkey->generated)
6889				goto nextkey;
6890
6891			dns_name_format(&tkey->name, namestr, sizeof(namestr));
6892			if (strcmp(namestr, target) == 0) {
6893				(*foundkeys)++;
6894				dns_rbtnodechain_invalidate(&chain);
6895				(void)dns_rbt_deletename(ring->keys,
6896							 &tkey->name,
6897							 ISC_FALSE);
6898				goto again;
6899			}
6900		}
6901
6902	nextkey:
6903		result = dns_rbtnodechain_next(&chain, &foundname, origin);
6904		if (result == ISC_R_NOMORE)
6905			break;
6906		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6907			dns_rbtnodechain_invalidate(&chain);
6908			return (result);
6909		}
6910	}
6911
6912	return (ISC_R_SUCCESS);
6913}
6914
6915isc_result_t
6916ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
6917	isc_result_t result;
6918	unsigned int n;
6919	dns_view_t *view;
6920	unsigned int foundkeys = 0;
6921	char *target;
6922	char *viewname;
6923
6924	(void)next_token(&command, " \t");  /* skip command name */
6925	target = next_token(&command, " \t");
6926	if (target == NULL)
6927		return (ISC_R_UNEXPECTEDEND);
6928	viewname = next_token(&command, " \t");
6929
6930	result = isc_task_beginexclusive(server->task);
6931	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6932	for (view = ISC_LIST_HEAD(server->viewlist);
6933	     view != NULL;
6934	     view = ISC_LIST_NEXT(view, link)) {
6935		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
6936			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
6937			result = delete_keynames(view->dynamickeys, target,
6938						 &foundkeys);
6939			RWUNLOCK(&view->dynamickeys->lock,
6940				 isc_rwlocktype_write);
6941			if (result != ISC_R_SUCCESS) {
6942				isc_task_endexclusive(server->task);
6943				return (result);
6944			}
6945		}
6946	}
6947	isc_task_endexclusive(server->task);
6948
6949	n = snprintf((char *)isc_buffer_used(text),
6950		     isc_buffer_availablelength(text),
6951		     "%d tsig keys deleted.\n", foundkeys);
6952	if (n >= isc_buffer_availablelength(text))
6953		return (ISC_R_NOSPACE);
6954	isc_buffer_add(text, n);
6955
6956	return (ISC_R_SUCCESS);
6957}
6958
6959static isc_result_t
6960list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
6961	     unsigned int *foundkeys)
6962{
6963	char namestr[DNS_NAME_FORMATSIZE];
6964	char creatorstr[DNS_NAME_FORMATSIZE];
6965	isc_result_t result;
6966	dns_rbtnodechain_t chain;
6967	dns_name_t foundname;
6968	dns_fixedname_t fixedorigin;
6969	dns_name_t *origin;
6970	dns_rbtnode_t *node;
6971	dns_tsigkey_t *tkey;
6972	unsigned int n;
6973	const char *viewname;
6974
6975	if (view != NULL)
6976		viewname = view->name;
6977	else
6978		viewname = "(global)";
6979
6980	dns_name_init(&foundname, NULL);
6981	dns_fixedname_init(&fixedorigin);
6982	origin = dns_fixedname_name(&fixedorigin);
6983	dns_rbtnodechain_init(&chain, ring->mctx);
6984	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
6985					origin);
6986	if (result == ISC_R_NOTFOUND) {
6987		dns_rbtnodechain_invalidate(&chain);
6988		return (ISC_R_SUCCESS);
6989	}
6990	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6991		dns_rbtnodechain_invalidate(&chain);
6992		return (result);
6993	}
6994
6995	for (;;) {
6996		node = NULL;
6997		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
6998		tkey = node->data;
6999
7000		if (tkey != NULL) {
7001			(*foundkeys)++;
7002			dns_name_format(&tkey->name, namestr, sizeof(namestr));
7003			if (tkey->generated) {
7004				dns_name_format(tkey->creator, creatorstr,
7005						sizeof(creatorstr));
7006				n = snprintf((char *)isc_buffer_used(text),
7007					     isc_buffer_availablelength(text),
7008					     "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
7009					     viewname, namestr, creatorstr);
7010			} else {
7011				n = snprintf((char *)isc_buffer_used(text),
7012					     isc_buffer_availablelength(text),
7013					     "view \"%s\"; type \"static\"; key \"%s\";\n",
7014					     viewname, namestr);
7015			}
7016			if (n >= isc_buffer_availablelength(text)) {
7017				dns_rbtnodechain_invalidate(&chain);
7018				return (ISC_R_NOSPACE);
7019			}
7020			isc_buffer_add(text, n);
7021		}
7022		result = dns_rbtnodechain_next(&chain, &foundname, origin);
7023		if (result == ISC_R_NOMORE)
7024			break;
7025		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7026			dns_rbtnodechain_invalidate(&chain);
7027			return (result);
7028		}
7029	}
7030
7031	return (ISC_R_SUCCESS);
7032}
7033
7034isc_result_t
7035ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
7036	isc_result_t result;
7037	unsigned int n;
7038	dns_view_t *view;
7039	unsigned int foundkeys = 0;
7040
7041	result = isc_task_beginexclusive(server->task);
7042	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7043	for (view = ISC_LIST_HEAD(server->viewlist);
7044	     view != NULL;
7045	     view = ISC_LIST_NEXT(view, link)) {
7046		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7047		result = list_keynames(view, view->statickeys, text,
7048				       &foundkeys);
7049		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7050		if (result != ISC_R_SUCCESS) {
7051			isc_task_endexclusive(server->task);
7052			return (result);
7053		}
7054		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7055		result = list_keynames(view, view->dynamickeys, text,
7056				       &foundkeys);
7057		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7058		if (result != ISC_R_SUCCESS) {
7059			isc_task_endexclusive(server->task);
7060			return (result);
7061		}
7062	}
7063	isc_task_endexclusive(server->task);
7064
7065	if (foundkeys == 0) {
7066		n = snprintf((char *)isc_buffer_used(text),
7067			     isc_buffer_availablelength(text),
7068			     "no tsig keys found.\n");
7069		if (n >= isc_buffer_availablelength(text))
7070			return (ISC_R_NOSPACE);
7071		isc_buffer_add(text, n);
7072	}
7073
7074	return (ISC_R_SUCCESS);
7075}
7076
7077/*
7078 * Act on a "sign" or "loadkeys" command from the command channel.
7079 */
7080isc_result_t
7081ns_server_rekey(ns_server_t *server, char *args) {
7082	isc_result_t result;
7083	dns_zone_t *zone = NULL;
7084	dns_zonetype_t type;
7085	isc_uint16_t keyopts;
7086	isc_boolean_t fullsign = ISC_FALSE;
7087
7088	if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
7089	    fullsign = ISC_TRUE;
7090
7091	result = zone_from_args(server, args, &zone, NULL);
7092	if (result != ISC_R_SUCCESS)
7093		return (result);
7094	if (zone == NULL)
7095		return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
7096
7097	type = dns_zone_gettype(zone);
7098	if (type != dns_zone_master) {
7099		dns_zone_detach(&zone);
7100		return (DNS_R_NOTMASTER);
7101	}
7102
7103	keyopts = dns_zone_getkeyopts(zone);
7104
7105	/* "rndc loadkeys" requires "auto-dnssec maintain". */
7106	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
7107		result = ISC_R_NOPERM;
7108	else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
7109		result = ISC_R_NOPERM;
7110	else
7111		dns_zone_rekey(zone, fullsign);
7112
7113	dns_zone_detach(&zone);
7114	return (result);
7115}
7116
7117/*
7118 * Act on a "freeze" or "thaw" command from the command channel.
7119 */
7120isc_result_t
7121ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
7122		 isc_buffer_t *text)
7123{
7124	isc_result_t result, tresult;
7125	dns_zone_t *zone = NULL;
7126	dns_zonetype_t type;
7127	char classstr[DNS_RDATACLASS_FORMATSIZE];
7128	char zonename[DNS_NAME_FORMATSIZE];
7129	dns_view_t *view;
7130	char *journal;
7131	const char *vname, *sep;
7132	isc_boolean_t frozen;
7133	const char *msg = NULL;
7134
7135	result = zone_from_args(server, args, &zone, NULL);
7136	if (result != ISC_R_SUCCESS)
7137		return (result);
7138	if (zone == NULL) {
7139		result = isc_task_beginexclusive(server->task);
7140		RUNTIME_CHECK(result == ISC_R_SUCCESS);
7141		tresult = ISC_R_SUCCESS;
7142		for (view = ISC_LIST_HEAD(server->viewlist);
7143		     view != NULL;
7144		     view = ISC_LIST_NEXT(view, link)) {
7145			result = dns_view_freezezones(view, freeze);
7146			if (result != ISC_R_SUCCESS &&
7147			    tresult == ISC_R_SUCCESS)
7148				tresult = result;
7149		}
7150		isc_task_endexclusive(server->task);
7151		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7152			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7153			      "%s all zones: %s",
7154			      freeze ? "freezing" : "thawing",
7155			      isc_result_totext(tresult));
7156		return (tresult);
7157	}
7158	type = dns_zone_gettype(zone);
7159	if (type != dns_zone_master) {
7160		dns_zone_detach(&zone);
7161		return (DNS_R_NOTMASTER);
7162	}
7163
7164	result = isc_task_beginexclusive(server->task);
7165	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7166	frozen = dns_zone_getupdatedisabled(zone);
7167	if (freeze) {
7168		if (frozen) {
7169			msg = "WARNING: The zone was already frozen.\n"
7170			      "Someone else may be editing it or "
7171			      "it may still be re-loading.";
7172			result = DNS_R_FROZEN;
7173		}
7174		if (result == ISC_R_SUCCESS) {
7175			result = dns_zone_flush(zone);
7176			if (result != ISC_R_SUCCESS)
7177				msg = "Flushing the zone updates to "
7178				      "disk failed.";
7179		}
7180		if (result == ISC_R_SUCCESS) {
7181			journal = dns_zone_getjournal(zone);
7182			if (journal != NULL)
7183				(void)isc_file_remove(journal);
7184		}
7185		if (result == ISC_R_SUCCESS)
7186			dns_zone_setupdatedisabled(zone, freeze);
7187	} else {
7188		if (frozen) {
7189			result = dns_zone_loadandthaw(zone);
7190			switch (result) {
7191			case ISC_R_SUCCESS:
7192			case DNS_R_UPTODATE:
7193				msg = "The zone reload and thaw was "
7194				      "successful.";
7195				result = ISC_R_SUCCESS;
7196				break;
7197			case DNS_R_CONTINUE:
7198				msg = "A zone reload and thaw was started.\n"
7199				      "Check the logs to see the result.";
7200				result = ISC_R_SUCCESS;
7201				break;
7202			}
7203		}
7204	}
7205	isc_task_endexclusive(server->task);
7206
7207	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
7208		isc_buffer_putmem(text, (const unsigned char *)msg,
7209				  strlen(msg) + 1);
7210
7211	view = dns_zone_getview(zone);
7212	if (strcmp(view->name, "_default") == 0 ||
7213	    strcmp(view->name, "_bind") == 0)
7214	{
7215		vname = "";
7216		sep = "";
7217	} else {
7218		vname = view->name;
7219		sep = " ";
7220	}
7221	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
7222			      sizeof(classstr));
7223	dns_name_format(dns_zone_getorigin(zone),
7224			zonename, sizeof(zonename));
7225	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7226		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7227		      "%s zone '%s/%s'%s%s: %s",
7228		      freeze ? "freezing" : "thawing",
7229		      zonename, classstr, sep, vname,
7230		      isc_result_totext(result));
7231	dns_zone_detach(&zone);
7232	return (result);
7233}
7234
7235#ifdef HAVE_LIBSCF
7236/*
7237 * This function adds a message for rndc to echo if named
7238 * is managed by smf and is also running chroot.
7239 */
7240isc_result_t
7241ns_smf_add_message(isc_buffer_t *text) {
7242	unsigned int n;
7243
7244	n = snprintf((char *)isc_buffer_used(text),
7245		isc_buffer_availablelength(text),
7246		"use svcadm(1M) to manage named");
7247	if (n >= isc_buffer_availablelength(text))
7248		return (ISC_R_NOSPACE);
7249	isc_buffer_add(text, n);
7250	return (ISC_R_SUCCESS);
7251}
7252#endif /* HAVE_LIBSCF */
7253
7254/*
7255 * Act on an "addzone" command from the command channel.
7256 */
7257isc_result_t
7258ns_server_add_zone(ns_server_t *server, char *args) {
7259	isc_result_t	     result;
7260	isc_buffer_t	     argbuf;
7261	size_t		     arglen;
7262	cfg_parser_t	    *parser = NULL;
7263	cfg_obj_t	    *config = NULL;
7264	const cfg_obj_t	    *vconfig = NULL;
7265	const cfg_obj_t	    *views = NULL;
7266	const cfg_obj_t     *parms = NULL;
7267	const cfg_obj_t     *obj = NULL;
7268	const cfg_listelt_t *element;
7269	const char	    *zonename;
7270	const char	    *classname = NULL;
7271	const char	    *argp;
7272	const char	    *viewname = NULL;
7273	dns_rdataclass_t     rdclass;
7274	dns_view_t	    *view = 0;
7275	isc_buffer_t	     buf, *nbuf = NULL;
7276	dns_name_t	     dnsname;
7277	dns_zone_t	    *zone = NULL;
7278	FILE		    *fp = NULL;
7279	struct cfg_context  *cfg = NULL;
7280
7281	/* Try to parse the argument string */
7282	arglen = strlen(args);
7283	isc_buffer_init(&argbuf, args, arglen);
7284	isc_buffer_add(&argbuf, strlen(args));
7285	CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser));
7286	CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf,
7287			       &config));
7288	CHECK(cfg_map_get(config, "addzone", &parms));
7289
7290	zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
7291	isc_buffer_init(&buf, zonename, strlen(zonename));
7292	isc_buffer_add(&buf, strlen(zonename));
7293	dns_name_init(&dnsname, NULL);
7294	isc_buffer_allocate(server->mctx, &nbuf, 256);
7295	dns_name_setbuffer(&dnsname, nbuf);
7296	CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
7297
7298	/* Make sense of optional class argument */
7299	obj = cfg_tuple_get(parms, "class");
7300	CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
7301	if (rdclass != dns_rdataclass_in && obj)
7302		classname = cfg_obj_asstring(obj);
7303
7304	/* Make sense of optional view argument */
7305	obj = cfg_tuple_get(parms, "view");
7306	if (obj && cfg_obj_isstring(obj))
7307		viewname = cfg_obj_asstring(obj);
7308	if (viewname == NULL || *viewname == '\0')
7309		viewname = "_default";
7310	CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
7311
7312	/* Are we accepting new zones? */
7313	if (view->new_zone_file == NULL) {
7314		result = ISC_R_NOPERM;
7315		goto cleanup;
7316	}
7317
7318	cfg = (struct cfg_context *) view->new_zone_config;
7319	if (cfg == NULL) {
7320		result = ISC_R_FAILURE;
7321		goto cleanup;
7322	}
7323
7324	/* Zone shouldn't already exist */
7325	result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone);
7326	if (result == ISC_R_SUCCESS) {
7327		result = ISC_R_EXISTS;
7328		goto cleanup;
7329	} else if (result == DNS_R_PARTIALMATCH) {
7330		/* Create our sub-zone anyway */
7331		dns_zone_detach(&zone);
7332		zone = NULL;
7333	}
7334	else if (result != ISC_R_NOTFOUND)
7335		goto cleanup;
7336
7337	/* Find the view statement */
7338	cfg_map_get(cfg->config, "view", &views);
7339	for (element = cfg_list_first(views);
7340	     element != NULL;
7341	     element = cfg_list_next(element))
7342	{
7343		const char *vname;
7344		vconfig = cfg_listelt_value(element);
7345		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
7346		if (vname && !strcasecmp(vname, viewname))
7347			break;
7348		vconfig = NULL;
7349	}
7350
7351	/* Open save file for write configuration */
7352	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
7353
7354	/* Mark view unfrozen so that zone can be added */
7355	dns_view_thaw(view);
7356	result = configure_zone(cfg->config, parms, vconfig,
7357				server->mctx, view, cfg->actx, ISC_FALSE);
7358	dns_view_freeze(view);
7359	if (result != ISC_R_SUCCESS) {
7360		goto cleanup;
7361	}
7362
7363	/* Is it there yet? */
7364	CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone));
7365
7366	/*
7367	 * Load the zone from the master file.  If this fails, we'll
7368	 * need to undo the configuration we've done already.
7369	 */
7370	result = dns_zone_loadnew(zone);
7371	if (result != ISC_R_SUCCESS) {
7372		dns_db_t *dbp = NULL;
7373
7374		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7375			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7376			      "addzone failed; reverting.");
7377
7378		/* If the zone loaded partially, unload it */
7379		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
7380			dns_db_detach(&dbp);
7381			dns_zone_unload(zone);
7382		}
7383
7384		/* Remove the zone from the zone table */
7385		dns_zt_unmount(view->zonetable, zone);
7386		goto cleanup;
7387	}
7388
7389	/* Flag the zone as having been added at runtime */
7390	dns_zone_setadded(zone, ISC_TRUE);
7391
7392	/* Emit just the zone name from args */
7393	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
7394	CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL));
7395	CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
7396
7397	/* Classname, if not default */
7398	if (classname != NULL && *classname != '\0') {
7399		CHECK(isc_stdio_write(classname, strlen(classname), 1, fp,
7400				      NULL));
7401		CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
7402	}
7403
7404	/* Find beginning of option block from args */
7405	for (argp = args; *argp; argp++, arglen--) {
7406		if (*argp == '{') {	/* Assume matching '}' */
7407			/* Add that to our file */
7408			CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL));
7409
7410			/* Make sure we end with a LF */
7411			if (argp[arglen-1] != '\n') {
7412				CHECK(isc_stdio_write("\n", 1, 1, fp, NULL));
7413			}
7414			break;
7415		}
7416	}
7417
7418	CHECK(isc_stdio_close(fp));
7419	fp = NULL;
7420	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7421				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7422				  "zone %s added to view %s via addzone",
7423				  zonename, viewname);
7424
7425	result = ISC_R_SUCCESS;
7426
7427 cleanup:
7428	if (fp != NULL)
7429		isc_stdio_close(fp);
7430	if (parser != NULL) {
7431		if (config != NULL)
7432			cfg_obj_destroy(parser, &config);
7433		cfg_parser_destroy(&parser);
7434	}
7435	if (zone != NULL)
7436		dns_zone_detach(&zone);
7437	if (view != NULL)
7438		dns_view_detach(&view);
7439	if (nbuf != NULL)
7440		isc_buffer_free(&nbuf);
7441
7442	return (result);
7443}
7444
7445/*
7446 * Act on a "delzone" command from the command channel.
7447 */
7448isc_result_t
7449ns_server_del_zone(ns_server_t *server, char *args) {
7450	isc_result_t	       result;
7451	dns_zone_t	      *zone = NULL;
7452	dns_view_t	      *view = NULL;
7453	dns_db_t	      *dbp = NULL;
7454	const char	      *filename = NULL;
7455	char		      *tmpname = NULL;
7456	char		       buf[1024];
7457	const char	      *zonename = NULL;
7458	size_t		       znamelen = 0;
7459	FILE		      *ifp = NULL, *ofp = NULL;
7460
7461	/* Parse parameters */
7462	CHECK(zone_from_args(server, args, &zone, &zonename));
7463	if (result != ISC_R_SUCCESS)
7464		return (result);
7465	if (zone == NULL) {
7466		result = ISC_R_UNEXPECTEDEND;
7467		goto cleanup;
7468	}
7469
7470	/*
7471	 * Was this zone originally added at runtime?
7472	 * If not, we can't delete it now.
7473	 */
7474	if (!dns_zone_getadded(zone)) {
7475		result = ISC_R_NOPERM;
7476		goto cleanup;
7477	}
7478
7479	if (zonename != NULL)
7480		znamelen = strlen(zonename);
7481
7482	/* Dig out configuration for this zone */
7483	view = dns_zone_getview(zone);
7484	filename = view->new_zone_file;
7485	if (filename == NULL) {
7486		/* No adding zones in this view */
7487		result = ISC_R_FAILURE;
7488		goto cleanup;
7489	}
7490
7491	/* Rewrite zone list */
7492	result = isc_stdio_open(filename, "r", &ifp);
7493	if (ifp != NULL && result == ISC_R_SUCCESS) {
7494		char *found = NULL, *p = NULL;
7495		size_t n;
7496
7497		/* Create a temporary file */
7498		CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename,
7499					(long)getpid()));
7500		if (!(tmpname = isc_mem_strdup(server->mctx, buf))) {
7501			result = ISC_R_NOMEMORY;
7502			goto cleanup;
7503		}
7504		CHECK(isc_stdio_open(tmpname, "w", &ofp));
7505
7506		/* Look for the entry for that zone */
7507		while (fgets(buf, 1024, ifp)) {
7508			/* A 'zone' line */
7509			if (strncasecmp(buf, "zone", 4)) {
7510				fputs(buf, ofp);
7511				continue;
7512			}
7513			p = buf+4;
7514
7515			/* Locate a name */
7516			while (*p &&
7517			       ((*p == '"') || isspace((unsigned char)*p)))
7518				p++;
7519
7520			/* Is that the zone we're looking for */
7521			if (strncasecmp(p, zonename, znamelen)) {
7522				fputs(buf, ofp);
7523				continue;
7524			}
7525
7526			/* And nothing else? */
7527			p += znamelen;
7528			if (isspace((unsigned char)*p) ||
7529			    *p == '"' || *p == '{') {
7530				/* This must be the entry */
7531				found = p;
7532				break;
7533			}
7534
7535			/* Spit it out, keep looking */
7536			fputs(buf, ofp);
7537		}
7538
7539		/* Skip over an option block (matching # of braces) */
7540		if (found) {
7541			int obrace = 0, cbrace = 0;
7542			for (;;) {
7543				while (*p) {
7544					if (*p == '{') obrace++;
7545					if (*p == '}') cbrace++;
7546					p++;
7547				}
7548				if (obrace && (obrace == cbrace))
7549					break;
7550				if (!fgets(buf, 1024, ifp))
7551					break;
7552				p = buf;
7553			}
7554
7555			/* Just spool the remainder of the file out */
7556			result = isc_stdio_read(buf, 1, 1024, ifp, &n);
7557			while (n > 0U) {
7558				if (result == ISC_R_EOF)
7559					result = ISC_R_SUCCESS;
7560				CHECK(result);
7561				isc_stdio_write(buf, 1, n, ofp, NULL);
7562				result = isc_stdio_read(buf, 1, 1024, ifp, &n);
7563			}
7564
7565			/* Move temporary into place */
7566			CHECK(isc_file_rename(tmpname, view->new_zone_file));
7567		} else {
7568			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7569				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
7570				      "deleted zone %s was missing from "
7571				      "new zone file", zonename);
7572			goto cleanup;
7573		}
7574	}
7575
7576	/* Stop answering for this zone */
7577	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
7578		dns_db_detach(&dbp);
7579		dns_zone_unload(zone);
7580	}
7581
7582	CHECK(dns_zt_unmount(view->zonetable, zone));
7583
7584	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7585				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7586				  "zone %s removed via delzone", zonename);
7587
7588	result = ISC_R_SUCCESS;
7589
7590 cleanup:
7591	if (ifp != NULL)
7592		isc_stdio_close(ifp);
7593	if (ofp != NULL) {
7594		isc_stdio_close(ofp);
7595		isc_file_remove(tmpname);
7596	}
7597	if (tmpname != NULL)
7598		isc_mem_free(server->mctx, tmpname);
7599	if (zone != NULL)
7600		dns_zone_detach(&zone);
7601
7602	return (result);
7603}
7604
7605static void
7606newzone_cfgctx_destroy(void **cfgp) {
7607	struct cfg_context *cfg;
7608
7609	REQUIRE(cfgp != NULL && *cfgp != NULL);
7610
7611	cfg = *cfgp;
7612
7613	if (cfg->actx != NULL)
7614		cfg_aclconfctx_detach(&cfg->actx);
7615
7616	if (cfg->parser != NULL) {
7617		if (cfg->config != NULL)
7618			cfg_obj_destroy(cfg->parser, &cfg->config);
7619		cfg_parser_destroy(&cfg->parser);
7620	}
7621	if (cfg->nzparser != NULL) {
7622		if (cfg->nzconfig != NULL)
7623			cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig);
7624		cfg_parser_destroy(&cfg->nzparser);
7625	}
7626
7627	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
7628	*cfgp = NULL;
7629}
7630