server.c revision 218384
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.520.12.21 2011-01-14 23:45:49 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <stdlib.h>
25#include <unistd.h>
26
27#include <isc/app.h>
28#include <isc/base64.h>
29#include <isc/dir.h>
30#include <isc/entropy.h>
31#include <isc/file.h>
32#include <isc/hash.h>
33#include <isc/httpd.h>
34#include <isc/lex.h>
35#include <isc/parseint.h>
36#include <isc/portset.h>
37#include <isc/print.h>
38#include <isc/resource.h>
39#include <isc/socket.h>
40#include <isc/stats.h>
41#include <isc/stdio.h>
42#include <isc/string.h>
43#include <isc/task.h>
44#include <isc/timer.h>
45#include <isc/util.h>
46#include <isc/xml.h>
47
48#include <isccfg/namedconf.h>
49
50#include <bind9/check.h>
51
52#include <dns/acache.h>
53#include <dns/adb.h>
54#include <dns/cache.h>
55#include <dns/db.h>
56#include <dns/dispatch.h>
57#ifdef DLZ
58#include <dns/dlz.h>
59#endif
60#include <dns/forward.h>
61#include <dns/journal.h>
62#include <dns/keytable.h>
63#include <dns/lib.h>
64#include <dns/master.h>
65#include <dns/masterdump.h>
66#include <dns/order.h>
67#include <dns/peer.h>
68#include <dns/portlist.h>
69#include <dns/rbt.h>
70#include <dns/rdataclass.h>
71#include <dns/rdataset.h>
72#include <dns/rdatastruct.h>
73#include <dns/resolver.h>
74#include <dns/rootns.h>
75#include <dns/secalg.h>
76#include <dns/stats.h>
77#include <dns/tkey.h>
78#include <dns/tsig.h>
79#include <dns/view.h>
80#include <dns/zone.h>
81#include <dns/zt.h>
82
83#include <dst/dst.h>
84#include <dst/result.h>
85
86#include <named/client.h>
87#include <named/config.h>
88#include <named/control.h>
89#include <named/interfacemgr.h>
90#include <named/log.h>
91#include <named/logconf.h>
92#include <named/lwresd.h>
93#include <named/main.h>
94#include <named/os.h>
95#include <named/server.h>
96#include <named/statschannel.h>
97#include <named/tkeyconf.h>
98#include <named/tsigconf.h>
99#include <named/zoneconf.h>
100#ifdef HAVE_LIBSCF
101#include <named/ns_smf_globals.h>
102#include <stdlib.h>
103#endif
104
105/*%
106 * Check an operation for failure.  Assumes that the function
107 * using it has a 'result' variable and a 'cleanup' label.
108 */
109#define CHECK(op) \
110	do { result = (op);					 \
111	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
112	} while (0)
113
114#define CHECKM(op, msg) \
115	do { result = (op);					  \
116	       if (result != ISC_R_SUCCESS) {			  \
117			isc_log_write(ns_g_lctx,		  \
118				      NS_LOGCATEGORY_GENERAL,	  \
119				      NS_LOGMODULE_SERVER,	  \
120				      ISC_LOG_ERROR,		  \
121				      "%s: %s", msg,		  \
122				      isc_result_totext(result)); \
123			goto cleanup;				  \
124		}						  \
125	} while (0)						  \
126
127#define CHECKMF(op, msg, file) \
128	do { result = (op);					  \
129	       if (result != ISC_R_SUCCESS) {			  \
130			isc_log_write(ns_g_lctx,		  \
131				      NS_LOGCATEGORY_GENERAL,	  \
132				      NS_LOGMODULE_SERVER,	  \
133				      ISC_LOG_ERROR,		  \
134				      "%s '%s': %s", msg, file,	  \
135				      isc_result_totext(result)); \
136			goto cleanup;				  \
137		}						  \
138	} while (0)						  \
139
140#define CHECKFATAL(op, msg) \
141	do { result = (op);					  \
142	       if (result != ISC_R_SUCCESS)			  \
143			fatal(msg, result);			  \
144	} while (0)						  \
145
146struct ns_dispatch {
147	isc_sockaddr_t			addr;
148	unsigned int			dispatchgen;
149	dns_dispatch_t			*dispatch;
150	ISC_LINK(struct ns_dispatch)	link;
151};
152
153struct dumpcontext {
154	isc_mem_t			*mctx;
155	isc_boolean_t			dumpcache;
156	isc_boolean_t			dumpzones;
157	FILE				*fp;
158	ISC_LIST(struct viewlistentry)	viewlist;
159	struct viewlistentry		*view;
160	struct zonelistentry		*zone;
161	dns_dumpctx_t			*mdctx;
162	dns_db_t			*db;
163	dns_db_t			*cache;
164	isc_task_t			*task;
165	dns_dbversion_t			*version;
166};
167
168struct viewlistentry {
169	dns_view_t			*view;
170	ISC_LINK(struct viewlistentry)	link;
171	ISC_LIST(struct zonelistentry)	zonelist;
172};
173
174struct zonelistentry {
175	dns_zone_t			*zone;
176	ISC_LINK(struct zonelistentry)	link;
177};
178
179/*
180 * These zones should not leak onto the Internet.
181 */
182static const struct {
183	const char	*zone;
184	isc_boolean_t	rfc1918;
185} empty_zones[] = {
186#ifdef notyet
187	/* RFC 1918 */
188	{ "10.IN-ADDR.ARPA", ISC_TRUE },
189	{ "16.172.IN-ADDR.ARPA", ISC_TRUE },
190	{ "17.172.IN-ADDR.ARPA", ISC_TRUE },
191	{ "18.172.IN-ADDR.ARPA", ISC_TRUE },
192	{ "19.172.IN-ADDR.ARPA", ISC_TRUE },
193	{ "20.172.IN-ADDR.ARPA", ISC_TRUE },
194	{ "21.172.IN-ADDR.ARPA", ISC_TRUE },
195	{ "22.172.IN-ADDR.ARPA", ISC_TRUE },
196	{ "23.172.IN-ADDR.ARPA", ISC_TRUE },
197	{ "24.172.IN-ADDR.ARPA", ISC_TRUE },
198	{ "25.172.IN-ADDR.ARPA", ISC_TRUE },
199	{ "26.172.IN-ADDR.ARPA", ISC_TRUE },
200	{ "27.172.IN-ADDR.ARPA", ISC_TRUE },
201	{ "28.172.IN-ADDR.ARPA", ISC_TRUE },
202	{ "29.172.IN-ADDR.ARPA", ISC_TRUE },
203	{ "30.172.IN-ADDR.ARPA", ISC_TRUE },
204	{ "31.172.IN-ADDR.ARPA", ISC_TRUE },
205	{ "168.192.IN-ADDR.ARPA", ISC_TRUE },
206#endif
207
208	/* RFC 5735 and RFC 5737 */
209	{ "0.IN-ADDR.ARPA", ISC_FALSE },	/* THIS NETWORK */
210	{ "127.IN-ADDR.ARPA", ISC_FALSE },	/* LOOPBACK */
211	{ "254.169.IN-ADDR.ARPA", ISC_FALSE },	/* LINK LOCAL */
212	{ "2.0.192.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET */
213	{ "100.51.198.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET 2 */
214	{ "113.0.203.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET 3 */
215	{ "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE },	/* BROADCAST */
216
217	/* Local IPv6 Unicast Addresses */
218	{ "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 },
219	{ "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 },
220	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
221	{ "D.F.IP6.ARPA", ISC_FALSE },
222	{ "8.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
223	{ "9.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
224	{ "A.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
225	{ "B.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
226
227	/* Example Prefix, RFC 3849. */
228	{ "8.B.D.0.1.0.0.2.IP6.ARPA", ISC_FALSE },
229
230	{ NULL, ISC_FALSE }
231};
232
233static void
234fatal(const char *msg, isc_result_t result);
235
236static void
237ns_server_reload(isc_task_t *task, isc_event_t *event);
238
239static isc_result_t
240ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
241			cfg_aclconfctx_t *actx,
242			isc_mem_t *mctx, ns_listenelt_t **target);
243static isc_result_t
244ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
245			 cfg_aclconfctx_t *actx,
246			 isc_mem_t *mctx, ns_listenlist_t **target);
247
248static isc_result_t
249configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
250		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
251
252static isc_result_t
253configure_alternates(const cfg_obj_t *config, dns_view_t *view,
254		     const cfg_obj_t *alternates);
255
256static isc_result_t
257configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
258	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
259	       cfg_aclconfctx_t *aclconf);
260
261static void
262end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
263
264/*%
265 * Configure a single view ACL at '*aclp'.  Get its configuration from
266 * 'vconfig' (for per-view configuration) and maybe from 'config'
267 */
268static isc_result_t
269configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
270		   const char *aclname, cfg_aclconfctx_t *actx,
271		   isc_mem_t *mctx, dns_acl_t **aclp)
272{
273	isc_result_t result;
274	const cfg_obj_t *maps[3];
275	const cfg_obj_t *aclobj = NULL;
276	int i = 0;
277
278	if (*aclp != NULL)
279		dns_acl_detach(aclp);
280	if (vconfig != NULL)
281		maps[i++] = cfg_tuple_get(vconfig, "options");
282	if (config != NULL) {
283		const cfg_obj_t *options = NULL;
284		(void)cfg_map_get(config, "options", &options);
285		if (options != NULL)
286			maps[i++] = options;
287	}
288	maps[i] = NULL;
289
290	(void)ns_config_get(maps, aclname, &aclobj);
291	if (aclobj == NULL)
292		/*
293		 * No value available.	*aclp == NULL.
294		 */
295		return (ISC_R_SUCCESS);
296
297	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
298				    actx, mctx, 0, aclp);
299
300	return (result);
301}
302
303
304/*%
305 * Configure a sortlist at '*aclp'.  Essentially the same as
306 * configure_view_acl() except it calls cfg_acl_fromconfig with a
307 * nest_level value of 2.
308 */
309static isc_result_t
310configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
311			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
312			dns_acl_t **aclp)
313{
314	isc_result_t result;
315	const cfg_obj_t *maps[3];
316	const cfg_obj_t *aclobj = NULL;
317	int i = 0;
318
319	if (*aclp != NULL)
320		dns_acl_detach(aclp);
321	if (vconfig != NULL)
322		maps[i++] = cfg_tuple_get(vconfig, "options");
323	if (config != NULL) {
324		const cfg_obj_t *options = NULL;
325		(void)cfg_map_get(config, "options", &options);
326		if (options != NULL)
327			maps[i++] = options;
328	}
329	maps[i] = NULL;
330
331	(void)ns_config_get(maps, "sortlist", &aclobj);
332	if (aclobj == NULL)
333		return (ISC_R_SUCCESS);
334
335	/*
336	 * Use a nest level of 3 for the "top level" of the sortlist;
337	 * this means each entry in the top three levels will be stored
338	 * as lists of separate, nested ACLs, rather than merged together
339	 * into IP tables as is usually done with ACLs.
340	 */
341	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
342				    actx, mctx, 3, aclp);
343
344	return (result);
345}
346
347static isc_result_t
348configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key,
349			 dns_keytable_t *keytable, isc_mem_t *mctx)
350{
351	dns_rdataclass_t viewclass;
352	dns_rdata_dnskey_t keystruct;
353	isc_uint32_t flags, proto, alg;
354	const char *keystr, *keynamestr;
355	unsigned char keydata[4096];
356	isc_buffer_t keydatabuf;
357	unsigned char rrdata[4096];
358	isc_buffer_t rrdatabuf;
359	isc_region_t r;
360	dns_fixedname_t fkeyname;
361	dns_name_t *keyname;
362	isc_buffer_t namebuf;
363	isc_result_t result;
364	dst_key_t *dstkey = NULL;
365
366	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
367	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
368	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
369	keyname = dns_fixedname_name(&fkeyname);
370	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
371
372	if (vconfig == NULL)
373		viewclass = dns_rdataclass_in;
374	else {
375		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
376		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
377					 &viewclass));
378	}
379	keystruct.common.rdclass = viewclass;
380	keystruct.common.rdtype = dns_rdatatype_dnskey;
381	/*
382	 * The key data in keystruct is not dynamically allocated.
383	 */
384	keystruct.mctx = NULL;
385
386	ISC_LINK_INIT(&keystruct.common, link);
387
388	if (flags > 0xffff)
389		CHECKM(ISC_R_RANGE, "key flags");
390	if (proto > 0xff)
391		CHECKM(ISC_R_RANGE, "key protocol");
392	if (alg > 0xff)
393		CHECKM(ISC_R_RANGE, "key algorithm");
394	keystruct.flags = (isc_uint16_t)flags;
395	keystruct.protocol = (isc_uint8_t)proto;
396	keystruct.algorithm = (isc_uint8_t)alg;
397
398	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
399	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
400
401	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
402	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
403	isc_buffer_usedregion(&keydatabuf, &r);
404	keystruct.datalen = r.length;
405	keystruct.data = r.base;
406
407	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
408	     keystruct.algorithm == DST_ALG_RSAMD5) &&
409	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
410		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
411			    "trusted key '%s' has a weak exponent",
412			    keynamestr);
413
414	CHECK(dns_rdata_fromstruct(NULL,
415				   keystruct.common.rdclass,
416				   keystruct.common.rdtype,
417				   &keystruct, &rrdatabuf));
418	dns_fixedname_init(&fkeyname);
419	isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
420	isc_buffer_add(&namebuf, strlen(keynamestr));
421	CHECK(dns_name_fromtext(keyname, &namebuf,
422				dns_rootname, ISC_FALSE,
423				NULL));
424	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
425			      mctx, &dstkey));
426
427	CHECK(dns_keytable_add(keytable, &dstkey));
428	INSIST(dstkey == NULL);
429	return (ISC_R_SUCCESS);
430
431 cleanup:
432	if (result == DST_R_NOCRYPTO) {
433		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
434			    "ignoring trusted key for '%s': no crypto support",
435			    keynamestr);
436		result = ISC_R_SUCCESS;
437	} else {
438		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
439			    "configuring trusted key for '%s': %s",
440			    keynamestr, isc_result_totext(result));
441		result = ISC_R_FAILURE;
442	}
443
444	if (dstkey != NULL)
445		dst_key_free(&dstkey);
446
447	return (result);
448}
449
450/*%
451 * Configure DNSSEC keys for a view.  Currently used only for
452 * the security roots.
453 *
454 * The per-view configuration values and the server-global defaults are read
455 * from 'vconfig' and 'config'.	 The variable to be configured is '*target'.
456 */
457static isc_result_t
458configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config,
459			  isc_mem_t *mctx, dns_keytable_t **target)
460{
461	isc_result_t result;
462	const cfg_obj_t *keys = NULL;
463	const cfg_obj_t *voptions = NULL;
464	const cfg_listelt_t *element, *element2;
465	const cfg_obj_t *keylist;
466	const cfg_obj_t *key;
467	dns_keytable_t *keytable = NULL;
468
469	CHECK(dns_keytable_create(mctx, &keytable));
470
471	if (vconfig != NULL)
472		voptions = cfg_tuple_get(vconfig, "options");
473
474	keys = NULL;
475	if (voptions != NULL)
476		(void)cfg_map_get(voptions, "trusted-keys", &keys);
477	if (keys == NULL)
478		(void)cfg_map_get(config, "trusted-keys", &keys);
479
480	for (element = cfg_list_first(keys);
481	     element != NULL;
482	     element = cfg_list_next(element))
483	{
484		keylist = cfg_listelt_value(element);
485		for (element2 = cfg_list_first(keylist);
486		     element2 != NULL;
487		     element2 = cfg_list_next(element2))
488		{
489			key = cfg_listelt_value(element2);
490			CHECK(configure_view_dnsseckey(vconfig, key,
491						       keytable, mctx));
492		}
493	}
494
495	dns_keytable_detach(target);
496	*target = keytable; /* Transfer ownership. */
497	keytable = NULL;
498	result = ISC_R_SUCCESS;
499
500 cleanup:
501	return (result);
502}
503
504static isc_result_t
505mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver)
506{
507	const cfg_listelt_t *element;
508	const cfg_obj_t *obj;
509	const char *str;
510	dns_fixedname_t fixed;
511	dns_name_t *name;
512	isc_boolean_t value;
513	isc_result_t result;
514	isc_buffer_t b;
515
516	dns_fixedname_init(&fixed);
517	name = dns_fixedname_name(&fixed);
518	for (element = cfg_list_first(mbs);
519	     element != NULL;
520	     element = cfg_list_next(element))
521	{
522		obj = cfg_listelt_value(element);
523		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
524		isc_buffer_init(&b, str, strlen(str));
525		isc_buffer_add(&b, strlen(str));
526		CHECK(dns_name_fromtext(name, &b, dns_rootname,
527					ISC_FALSE, NULL));
528		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
529		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
530	}
531
532	result = ISC_R_SUCCESS;
533
534 cleanup:
535	return (result);
536}
537
538/*%
539 * Get a dispatch appropriate for the resolver of a given view.
540 */
541static isc_result_t
542get_view_querysource_dispatch(const cfg_obj_t **maps,
543			      int af, dns_dispatch_t **dispatchp,
544			      isc_boolean_t is_firstview)
545{
546	isc_result_t result;
547	dns_dispatch_t *disp;
548	isc_sockaddr_t sa;
549	unsigned int attrs, attrmask;
550	const cfg_obj_t *obj = NULL;
551	unsigned int maxdispatchbuffers;
552
553	/*
554	 * Make compiler happy.
555	 */
556	result = ISC_R_FAILURE;
557
558	switch (af) {
559	case AF_INET:
560		result = ns_config_get(maps, "query-source", &obj);
561		INSIST(result == ISC_R_SUCCESS);
562		break;
563	case AF_INET6:
564		result = ns_config_get(maps, "query-source-v6", &obj);
565		INSIST(result == ISC_R_SUCCESS);
566		break;
567	default:
568		INSIST(0);
569	}
570
571	sa = *(cfg_obj_assockaddr(obj));
572	INSIST(isc_sockaddr_pf(&sa) == af);
573
574	/*
575	 * If we don't support this address family, we're done!
576	 */
577	switch (af) {
578	case AF_INET:
579		result = isc_net_probeipv4();
580		break;
581	case AF_INET6:
582		result = isc_net_probeipv6();
583		break;
584	default:
585		INSIST(0);
586	}
587	if (result != ISC_R_SUCCESS)
588		return (ISC_R_SUCCESS);
589
590	/*
591	 * Try to find a dispatcher that we can share.
592	 */
593	attrs = 0;
594	attrs |= DNS_DISPATCHATTR_UDP;
595	switch (af) {
596	case AF_INET:
597		attrs |= DNS_DISPATCHATTR_IPV4;
598		break;
599	case AF_INET6:
600		attrs |= DNS_DISPATCHATTR_IPV6;
601		break;
602	}
603	if (isc_sockaddr_getport(&sa) == 0) {
604		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
605		maxdispatchbuffers = 4096;
606	} else {
607		INSIST(obj != NULL);
608		if (is_firstview) {
609			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
610				    "using specific query-source port "
611				    "suppresses port randomization and can be "
612				    "insecure.");
613		}
614		maxdispatchbuffers = 1000;
615	}
616
617	attrmask = 0;
618	attrmask |= DNS_DISPATCHATTR_UDP;
619	attrmask |= DNS_DISPATCHATTR_TCP;
620	attrmask |= DNS_DISPATCHATTR_IPV4;
621	attrmask |= DNS_DISPATCHATTR_IPV6;
622
623	disp = NULL;
624	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
625				     ns_g_taskmgr, &sa, 4096,
626				     maxdispatchbuffers, 32768, 16411, 16433,
627				     attrs, attrmask, &disp);
628	if (result != ISC_R_SUCCESS) {
629		isc_sockaddr_t any;
630		char buf[ISC_SOCKADDR_FORMATSIZE];
631
632		switch (af) {
633		case AF_INET:
634			isc_sockaddr_any(&any);
635			break;
636		case AF_INET6:
637			isc_sockaddr_any6(&any);
638			break;
639		}
640		if (isc_sockaddr_equal(&sa, &any))
641			return (ISC_R_SUCCESS);
642		isc_sockaddr_format(&sa, buf, sizeof(buf));
643		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
644			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
645			      "could not get query source dispatcher (%s)",
646			      buf);
647		return (result);
648	}
649
650	*dispatchp = disp;
651
652	return (ISC_R_SUCCESS);
653}
654
655static isc_result_t
656configure_order(dns_order_t *order, const cfg_obj_t *ent) {
657	dns_rdataclass_t rdclass;
658	dns_rdatatype_t rdtype;
659	const cfg_obj_t *obj;
660	dns_fixedname_t fixed;
661	unsigned int mode = 0;
662	const char *str;
663	isc_buffer_t b;
664	isc_result_t result;
665	isc_boolean_t addroot;
666
667	result = ns_config_getclass(cfg_tuple_get(ent, "class"),
668				    dns_rdataclass_any, &rdclass);
669	if (result != ISC_R_SUCCESS)
670		return (result);
671
672	result = ns_config_gettype(cfg_tuple_get(ent, "type"),
673				   dns_rdatatype_any, &rdtype);
674	if (result != ISC_R_SUCCESS)
675		return (result);
676
677	obj = cfg_tuple_get(ent, "name");
678	if (cfg_obj_isstring(obj))
679		str = cfg_obj_asstring(obj);
680	else
681		str = "*";
682	addroot = ISC_TF(strcmp(str, "*") == 0);
683	isc_buffer_init(&b, str, strlen(str));
684	isc_buffer_add(&b, strlen(str));
685	dns_fixedname_init(&fixed);
686	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
687				   dns_rootname, ISC_FALSE, NULL);
688	if (result != ISC_R_SUCCESS)
689		return (result);
690
691	obj = cfg_tuple_get(ent, "ordering");
692	INSIST(cfg_obj_isstring(obj));
693	str = cfg_obj_asstring(obj);
694	if (!strcasecmp(str, "fixed"))
695		mode = DNS_RDATASETATTR_FIXEDORDER;
696	else if (!strcasecmp(str, "random"))
697		mode = DNS_RDATASETATTR_RANDOMIZE;
698	else if (!strcasecmp(str, "cyclic"))
699		mode = 0;
700	else
701		INSIST(0);
702
703	/*
704	 * "*" should match everything including the root (BIND 8 compat).
705	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
706	 * explicit entry for "." when the name is "*".
707	 */
708	if (addroot) {
709		result = dns_order_add(order, dns_rootname,
710				       rdtype, rdclass, mode);
711		if (result != ISC_R_SUCCESS)
712			return (result);
713	}
714
715	return (dns_order_add(order, dns_fixedname_name(&fixed),
716			      rdtype, rdclass, mode));
717}
718
719static isc_result_t
720configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
721	isc_netaddr_t na;
722	dns_peer_t *peer;
723	const cfg_obj_t *obj;
724	const char *str;
725	isc_result_t result;
726	unsigned int prefixlen;
727
728	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
729
730	peer = NULL;
731	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
732	if (result != ISC_R_SUCCESS)
733		return (result);
734
735	obj = NULL;
736	(void)cfg_map_get(cpeer, "bogus", &obj);
737	if (obj != NULL)
738		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
739
740	obj = NULL;
741	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
742	if (obj != NULL)
743		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
744
745	obj = NULL;
746	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
747	if (obj != NULL)
748		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
749
750	obj = NULL;
751	(void)cfg_map_get(cpeer, "request-nsid", &obj);
752	if (obj != NULL)
753		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
754
755	obj = NULL;
756	(void)cfg_map_get(cpeer, "edns", &obj);
757	if (obj != NULL)
758		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
759
760	obj = NULL;
761	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
762	if (obj != NULL) {
763		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
764		if (udpsize < 512)
765			udpsize = 512;
766		if (udpsize > 4096)
767			udpsize = 4096;
768		CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
769	}
770
771	obj = NULL;
772	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
773	if (obj != NULL) {
774		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
775		if (udpsize < 512)
776			udpsize = 512;
777		if (udpsize > 4096)
778			udpsize = 4096;
779		CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
780	}
781
782	obj = NULL;
783	(void)cfg_map_get(cpeer, "transfers", &obj);
784	if (obj != NULL)
785		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
786
787	obj = NULL;
788	(void)cfg_map_get(cpeer, "transfer-format", &obj);
789	if (obj != NULL) {
790		str = cfg_obj_asstring(obj);
791		if (strcasecmp(str, "many-answers") == 0)
792			CHECK(dns_peer_settransferformat(peer,
793							 dns_many_answers));
794		else if (strcasecmp(str, "one-answer") == 0)
795			CHECK(dns_peer_settransferformat(peer,
796							 dns_one_answer));
797		else
798			INSIST(0);
799	}
800
801	obj = NULL;
802	(void)cfg_map_get(cpeer, "keys", &obj);
803	if (obj != NULL) {
804		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
805		if (result != ISC_R_SUCCESS)
806			goto cleanup;
807	}
808
809	obj = NULL;
810	if (na.family == AF_INET)
811		(void)cfg_map_get(cpeer, "transfer-source", &obj);
812	else
813		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
814	if (obj != NULL) {
815		result = dns_peer_settransfersource(peer,
816						    cfg_obj_assockaddr(obj));
817		if (result != ISC_R_SUCCESS)
818			goto cleanup;
819		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
820	}
821
822	obj = NULL;
823	if (na.family == AF_INET)
824		(void)cfg_map_get(cpeer, "notify-source", &obj);
825	else
826		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
827	if (obj != NULL) {
828		result = dns_peer_setnotifysource(peer,
829						  cfg_obj_assockaddr(obj));
830		if (result != ISC_R_SUCCESS)
831			goto cleanup;
832		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
833	}
834
835	obj = NULL;
836	if (na.family == AF_INET)
837		(void)cfg_map_get(cpeer, "query-source", &obj);
838	else
839		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
840	if (obj != NULL) {
841		result = dns_peer_setquerysource(peer,
842						 cfg_obj_assockaddr(obj));
843		if (result != ISC_R_SUCCESS)
844			goto cleanup;
845		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
846	}
847
848	*peerp = peer;
849	return (ISC_R_SUCCESS);
850
851 cleanup:
852	dns_peer_detach(&peer);
853	return (result);
854}
855
856static isc_result_t
857disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
858	isc_result_t result;
859	const cfg_obj_t *algorithms;
860	const cfg_listelt_t *element;
861	const char *str;
862	dns_fixedname_t fixed;
863	dns_name_t *name;
864	isc_buffer_t b;
865
866	dns_fixedname_init(&fixed);
867	name = dns_fixedname_name(&fixed);
868	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
869	isc_buffer_init(&b, str, strlen(str));
870	isc_buffer_add(&b, strlen(str));
871	CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL));
872
873	algorithms = cfg_tuple_get(disabled, "algorithms");
874	for (element = cfg_list_first(algorithms);
875	     element != NULL;
876	     element = cfg_list_next(element))
877	{
878		isc_textregion_t r;
879		dns_secalg_t alg;
880
881		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
882		r.length = strlen(r.base);
883
884		result = dns_secalg_fromtext(&alg, &r);
885		if (result != ISC_R_SUCCESS) {
886			isc_uint8_t ui;
887			result = isc_parse_uint8(&ui, r.base, 10);
888			alg = ui;
889		}
890		if (result != ISC_R_SUCCESS) {
891			cfg_obj_log(cfg_listelt_value(element),
892				    ns_g_lctx, ISC_LOG_ERROR,
893				    "invalid algorithm");
894			CHECK(result);
895		}
896		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
897	}
898 cleanup:
899	return (result);
900}
901
902static isc_boolean_t
903on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
904	const cfg_listelt_t *element;
905	dns_fixedname_t fixed;
906	dns_name_t *name;
907	isc_result_t result;
908	const cfg_obj_t *value;
909	const char *str;
910	isc_buffer_t b;
911
912	dns_fixedname_init(&fixed);
913	name = dns_fixedname_name(&fixed);
914
915	for (element = cfg_list_first(disablelist);
916	     element != NULL;
917	     element = cfg_list_next(element))
918	{
919		value = cfg_listelt_value(element);
920		str = cfg_obj_asstring(value);
921		isc_buffer_init(&b, str, strlen(str));
922		isc_buffer_add(&b, strlen(str));
923		result = dns_name_fromtext(name, &b, dns_rootname,
924					   ISC_TRUE, NULL);
925		RUNTIME_CHECK(result == ISC_R_SUCCESS);
926		if (dns_name_equal(name, zonename))
927			return (ISC_TRUE);
928	}
929	return (ISC_FALSE);
930}
931
932static void
933check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
934	     isc_mem_t *mctx)
935{
936	char **argv = NULL;
937	unsigned int i;
938	isc_result_t result;
939
940	result = dns_zone_getdbtype(*zonep, &argv, mctx);
941	if (result != ISC_R_SUCCESS) {
942		dns_zone_detach(zonep);
943		return;
944	}
945
946	/*
947	 * Check that all the arguments match.
948	 */
949	for (i = 0; i < dbtypec; i++)
950		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
951			dns_zone_detach(zonep);
952			break;
953		}
954
955	/*
956	 * Check that there are not extra arguments.
957	 */
958	if (i == dbtypec && argv[i] != NULL)
959		dns_zone_detach(zonep);
960	isc_mem_free(mctx, argv);
961}
962
963static isc_result_t
964setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
965	isc_result_t result;
966	isc_stats_t *zoneqrystats;
967
968	zoneqrystats = NULL;
969	if (on) {
970		result = isc_stats_create(mctx, &zoneqrystats,
971					  dns_nsstatscounter_max);
972		if (result != ISC_R_SUCCESS)
973			return (result);
974	}
975	dns_zone_setrequeststats(zone, zoneqrystats);
976	if (zoneqrystats != NULL)
977		isc_stats_detach(&zoneqrystats);
978
979	return (ISC_R_SUCCESS);
980}
981
982static isc_boolean_t
983cache_reusable(dns_view_t *originview, dns_view_t *view,
984	       isc_boolean_t new_zero_no_soattl)
985{
986	if (originview->checknames != view->checknames ||
987	    dns_resolver_getzeronosoattl(originview->resolver) !=
988	    new_zero_no_soattl ||
989	    originview->acceptexpired != view->acceptexpired ||
990	    originview->enablevalidation != view->enablevalidation ||
991	    originview->maxcachettl != view->maxcachettl ||
992	    originview->maxncachettl != view->maxncachettl) {
993		return (ISC_FALSE);
994	}
995
996	return (ISC_TRUE);
997}
998
999/*
1000 * Configure 'view' according to 'vconfig', taking defaults from 'config'
1001 * where values are missing in 'vconfig'.
1002 *
1003 * When configuring the default view, 'vconfig' will be NULL and the
1004 * global defaults in 'config' used exclusively.
1005 */
1006static isc_result_t
1007configure_view(dns_view_t *view, const cfg_obj_t *config,
1008	       const cfg_obj_t *vconfig, isc_mem_t *mctx,
1009	       cfg_aclconfctx_t *actx, isc_boolean_t need_hints)
1010{
1011	const cfg_obj_t *maps[4];
1012	const cfg_obj_t *cfgmaps[3];
1013	const cfg_obj_t *options = NULL;
1014	const cfg_obj_t *voptions = NULL;
1015	const cfg_obj_t *forwardtype;
1016	const cfg_obj_t *forwarders;
1017	const cfg_obj_t *alternates;
1018	const cfg_obj_t *zonelist;
1019#ifdef DLZ
1020	const cfg_obj_t *dlz;
1021	unsigned int dlzargc;
1022	char **dlzargv;
1023#endif
1024	const cfg_obj_t *disabled;
1025	const cfg_obj_t *obj;
1026	const cfg_listelt_t *element;
1027	in_port_t port;
1028	dns_cache_t *cache = NULL;
1029	isc_result_t result;
1030	isc_uint32_t max_adb_size;
1031	isc_uint32_t max_cache_size;
1032	isc_uint32_t max_acache_size;
1033	isc_uint32_t lame_ttl;
1034	dns_tsig_keyring_t *ring;
1035	dns_view_t *pview = NULL;	/* Production view */
1036	isc_mem_t *cmctx;
1037	dns_dispatch_t *dispatch4 = NULL;
1038	dns_dispatch_t *dispatch6 = NULL;
1039	isc_boolean_t reused_cache = ISC_FALSE;
1040	int i;
1041	const char *str;
1042	dns_order_t *order = NULL;
1043	isc_uint32_t udpsize;
1044	unsigned int resopts = 0;
1045	dns_zone_t *zone = NULL;
1046	isc_uint32_t max_clients_per_query;
1047	const char *sep = ": view ";
1048	const char *viewname = view->name;
1049	const char *forview = " for view ";
1050	isc_boolean_t rfc1918;
1051	isc_boolean_t empty_zones_enable;
1052	const cfg_obj_t *disablelist = NULL;
1053	isc_stats_t *resstats = NULL;
1054	dns_stats_t *resquerystats = NULL;
1055	isc_boolean_t zero_no_soattl;
1056
1057	REQUIRE(DNS_VIEW_VALID(view));
1058
1059	cmctx = NULL;
1060
1061	if (config != NULL)
1062		(void)cfg_map_get(config, "options", &options);
1063
1064	i = 0;
1065	if (vconfig != NULL) {
1066		voptions = cfg_tuple_get(vconfig, "options");
1067		maps[i++] = voptions;
1068	}
1069	if (options != NULL)
1070		maps[i++] = options;
1071	maps[i++] = ns_g_defaults;
1072	maps[i] = NULL;
1073
1074	i = 0;
1075	if (voptions != NULL)
1076		cfgmaps[i++] = voptions;
1077	if (config != NULL)
1078		cfgmaps[i++] = config;
1079	cfgmaps[i] = NULL;
1080
1081	if (!strcmp(viewname, "_default")) {
1082		sep = "";
1083		viewname = "";
1084		forview = "";
1085	}
1086
1087	/*
1088	 * Set the view's port number for outgoing queries.
1089	 */
1090	CHECKM(ns_config_getport(config, &port), "port");
1091	dns_view_setdstport(view, port);
1092
1093	/*
1094	 * Create additional cache for this view and zones under the view
1095	 * if explicitly enabled.
1096	 * XXX950 default to on.
1097	 */
1098	obj = NULL;
1099	(void)ns_config_get(maps, "acache-enable", &obj);
1100	if (obj != NULL && cfg_obj_asboolean(obj)) {
1101		cmctx = NULL;
1102		CHECK(isc_mem_create(0, 0, &cmctx));
1103		CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
1104					ns_g_timermgr));
1105		isc_mem_setname(cmctx, "acache", NULL);
1106		isc_mem_detach(&cmctx);
1107	}
1108	if (view->acache != NULL) {
1109		obj = NULL;
1110		result = ns_config_get(maps, "acache-cleaning-interval", &obj);
1111		INSIST(result == ISC_R_SUCCESS);
1112		dns_acache_setcleaninginterval(view->acache,
1113					       cfg_obj_asuint32(obj) * 60);
1114
1115		obj = NULL;
1116		result = ns_config_get(maps, "max-acache-size", &obj);
1117		INSIST(result == ISC_R_SUCCESS);
1118		if (cfg_obj_isstring(obj)) {
1119			str = cfg_obj_asstring(obj);
1120			INSIST(strcasecmp(str, "unlimited") == 0);
1121			max_acache_size = ISC_UINT32_MAX;
1122		} else {
1123			isc_resourcevalue_t value;
1124
1125			value = cfg_obj_asuint64(obj);
1126			if (value > ISC_UINT32_MAX) {
1127				cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1128					    "'max-acache-size "
1129					    "%" ISC_PRINT_QUADFORMAT
1130					    "d' is too large",
1131					    value);
1132				result = ISC_R_RANGE;
1133				goto cleanup;
1134			}
1135			max_acache_size = (isc_uint32_t)value;
1136		}
1137		dns_acache_setcachesize(view->acache, max_acache_size);
1138	}
1139
1140	CHECK(configure_view_acl(vconfig, config, "allow-query", actx,
1141				 ns_g_mctx, &view->queryacl));
1142
1143	if (view->queryacl == NULL) {
1144		CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", actx,
1145					 ns_g_mctx, &view->queryacl));
1146	}
1147
1148	/*
1149	 * Configure the zones.
1150	 */
1151	zonelist = NULL;
1152	if (voptions != NULL)
1153		(void)cfg_map_get(voptions, "zone", &zonelist);
1154	else
1155		(void)cfg_map_get(config, "zone", &zonelist);
1156	for (element = cfg_list_first(zonelist);
1157	     element != NULL;
1158	     element = cfg_list_next(element))
1159	{
1160		const cfg_obj_t *zconfig = cfg_listelt_value(element);
1161		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
1162				     actx));
1163	}
1164
1165#ifdef DLZ
1166	/*
1167	 * Create Dynamically Loadable Zone driver.
1168	 */
1169	dlz = NULL;
1170	if (voptions != NULL)
1171		(void)cfg_map_get(voptions, "dlz", &dlz);
1172	else
1173		(void)cfg_map_get(config, "dlz", &dlz);
1174
1175	obj = NULL;
1176	if (dlz != NULL) {
1177		(void)cfg_map_get(cfg_tuple_get(dlz, "options"),
1178				  "database", &obj);
1179		if (obj != NULL) {
1180			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
1181			if (s == NULL) {
1182				result = ISC_R_NOMEMORY;
1183				goto cleanup;
1184			}
1185
1186			result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
1187			if (result != ISC_R_SUCCESS) {
1188				isc_mem_free(mctx, s);
1189				goto cleanup;
1190			}
1191
1192			obj = cfg_tuple_get(dlz, "name");
1193			result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),
1194					       dlzargv[0], dlzargc, dlzargv,
1195					       &view->dlzdatabase);
1196			isc_mem_free(mctx, s);
1197			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
1198			if (result != ISC_R_SUCCESS)
1199				goto cleanup;
1200		}
1201	}
1202#endif
1203
1204	/*
1205	 * Obtain configuration parameters that affect the decision of whether
1206	 * we can reuse/share an existing cache.
1207	 */
1208	/* Check-names. */
1209	obj = NULL;
1210	result = ns_checknames_get(maps, "response", &obj);
1211	INSIST(result == ISC_R_SUCCESS);
1212
1213	str = cfg_obj_asstring(obj);
1214	if (strcasecmp(str, "fail") == 0) {
1215		resopts |= DNS_RESOLVER_CHECKNAMES |
1216			DNS_RESOLVER_CHECKNAMESFAIL;
1217		view->checknames = ISC_TRUE;
1218	} else if (strcasecmp(str, "warn") == 0) {
1219		resopts |= DNS_RESOLVER_CHECKNAMES;
1220		view->checknames = ISC_FALSE;
1221	} else if (strcasecmp(str, "ignore") == 0) {
1222		view->checknames = ISC_FALSE;
1223	} else
1224		INSIST(0);
1225
1226	obj = NULL;
1227	result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
1228	INSIST(result == ISC_R_SUCCESS);
1229	zero_no_soattl = cfg_obj_asboolean(obj);
1230
1231	obj = NULL;
1232	result = ns_config_get(maps, "dnssec-accept-expired", &obj);
1233	INSIST(result == ISC_R_SUCCESS);
1234	view->acceptexpired = cfg_obj_asboolean(obj);
1235
1236	obj = NULL;
1237	result = ns_config_get(maps, "dnssec-validation", &obj);
1238	INSIST(result == ISC_R_SUCCESS);
1239	view->enablevalidation = cfg_obj_asboolean(obj);
1240
1241	obj = NULL;
1242	result = ns_config_get(maps, "max-cache-ttl", &obj);
1243	INSIST(result == ISC_R_SUCCESS);
1244	view->maxcachettl = cfg_obj_asuint32(obj);
1245
1246	obj = NULL;
1247	result = ns_config_get(maps, "max-ncache-ttl", &obj);
1248	INSIST(result == ISC_R_SUCCESS);
1249	view->maxncachettl = cfg_obj_asuint32(obj);
1250	if (view->maxncachettl > 7 * 24 * 3600)
1251		view->maxncachettl = 7 * 24 * 3600;
1252
1253	/*
1254	 * Configure the view's cache.  Try to reuse an existing
1255	 * cache if possible, otherwise create a new cache.
1256	 * Note that the ADB is not preserved in either case.
1257	 * When a matching view is found, the associated statistics are
1258	 * also retrieved and reused.
1259	 *
1260	 * XXX Determining when it is safe to reuse a cache is tricky.
1261	 * When the view's configuration changes, the cached data may become
1262	 * invalid because it reflects our old view of the world.  We check
1263	 * some of the configuration parameters that could invalidate the cache,
1264	 * but there are other configuration options that should be checked.
1265	 * For example, if a view uses a forwarder, changes in the forwarder
1266	 * configuration may invalidate the cache.  At the moment, it's the
1267	 * administrator's responsibility to ensure these configuration options
1268	 * don't invalidate reusing.
1269	 */
1270	result = dns_viewlist_find(&ns_g_server->viewlist,
1271				   view->name, view->rdclass,
1272				   &pview);
1273	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1274		goto cleanup;
1275	if (pview != NULL) {
1276		if (cache_reusable(pview, view, zero_no_soattl)) {
1277			INSIST(pview->cache != NULL);
1278			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1279				      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3),
1280				      "reusing existing cache");
1281			reused_cache = ISC_TRUE;
1282			dns_cache_attach(pview->cache, &cache);
1283		} else {
1284			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1285				      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
1286				      "cache cannot be reused for view %s "
1287				      "due to configuration parameter mismatch",
1288				      view->name);
1289		}
1290		dns_view_getresstats(pview, &resstats);
1291		dns_view_getresquerystats(pview, &resquerystats);
1292		dns_view_detach(&pview);
1293	}
1294	if (cache == NULL) {
1295		CHECK(isc_mem_create(0, 0, &cmctx));
1296		CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr,
1297				       view->rdclass, "rbt", 0, NULL, &cache));
1298		isc_mem_setname(cmctx, "cache", NULL);
1299	}
1300	dns_view_setcache(view, cache);
1301
1302	/*
1303	 * cache-file cannot be inherited if views are present, but this
1304	 * should be caught by the configuration checking stage.
1305	 */
1306	obj = NULL;
1307	result = ns_config_get(maps, "cache-file", &obj);
1308	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
1309		CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
1310		if (!reused_cache)
1311			CHECK(dns_cache_load(cache));
1312	}
1313
1314	obj = NULL;
1315	result = ns_config_get(maps, "cleaning-interval", &obj);
1316	INSIST(result == ISC_R_SUCCESS);
1317	dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60);
1318
1319	obj = NULL;
1320	result = ns_config_get(maps, "max-cache-size", &obj);
1321	INSIST(result == ISC_R_SUCCESS);
1322	if (cfg_obj_isstring(obj)) {
1323		str = cfg_obj_asstring(obj);
1324		INSIST(strcasecmp(str, "unlimited") == 0);
1325		max_cache_size = ISC_UINT32_MAX;
1326	} else {
1327		isc_resourcevalue_t value;
1328		value = cfg_obj_asuint64(obj);
1329		if (value > ISC_UINT32_MAX) {
1330			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1331				    "'max-cache-size "
1332				    "%" ISC_PRINT_QUADFORMAT "d' is too large",
1333				    value);
1334			result = ISC_R_RANGE;
1335			goto cleanup;
1336		}
1337		max_cache_size = (isc_uint32_t)value;
1338	}
1339	dns_cache_setcachesize(cache, max_cache_size);
1340
1341	dns_cache_detach(&cache);
1342
1343	/*
1344	 * Resolver.
1345	 *
1346	 * XXXRTH  Hardwired number of tasks.
1347	 */
1348	CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4,
1349					    ISC_TF(ISC_LIST_PREV(view, link)
1350						   == NULL)));
1351	CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6,
1352					    ISC_TF(ISC_LIST_PREV(view, link)
1353						   == NULL)));
1354	if (dispatch4 == NULL && dispatch6 == NULL) {
1355		UNEXPECTED_ERROR(__FILE__, __LINE__,
1356				 "unable to obtain neither an IPv4 nor"
1357				 " an IPv6 dispatch");
1358		result = ISC_R_UNEXPECTED;
1359		goto cleanup;
1360	}
1361	CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
1362				      ns_g_socketmgr, ns_g_timermgr,
1363				      resopts, ns_g_dispatchmgr,
1364				      dispatch4, dispatch6));
1365
1366	if (resstats == NULL) {
1367		CHECK(isc_stats_create(mctx, &resstats,
1368				       dns_resstatscounter_max));
1369	}
1370	dns_view_setresstats(view, resstats);
1371	if (resquerystats == NULL)
1372		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
1373	dns_view_setresquerystats(view, resquerystats);
1374
1375	/*
1376	 * Set the ADB cache size to 1/8th of the max-cache-size.
1377	 */
1378	max_adb_size = 0;
1379	if (max_cache_size != 0) {
1380		max_adb_size = max_cache_size / 8;
1381		if (max_adb_size == 0)
1382			max_adb_size = 1;	/* Force minimum. */
1383	}
1384	dns_adb_setadbsize(view->adb, max_adb_size);
1385
1386	/*
1387	 * Set resolver's lame-ttl.
1388	 */
1389	obj = NULL;
1390	result = ns_config_get(maps, "lame-ttl", &obj);
1391	INSIST(result == ISC_R_SUCCESS);
1392	lame_ttl = cfg_obj_asuint32(obj);
1393	if (lame_ttl > 1800)
1394		lame_ttl = 1800;
1395	dns_resolver_setlamettl(view->resolver, lame_ttl);
1396
1397	/*
1398	 * Set the resolver's EDNS UDP size.
1399	 */
1400	obj = NULL;
1401	result = ns_config_get(maps, "edns-udp-size", &obj);
1402	INSIST(result == ISC_R_SUCCESS);
1403	udpsize = cfg_obj_asuint32(obj);
1404	if (udpsize < 512)
1405		udpsize = 512;
1406	if (udpsize > 4096)
1407		udpsize = 4096;
1408	dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
1409
1410	/*
1411	 * Set the maximum UDP response size.
1412	 */
1413	obj = NULL;
1414	result = ns_config_get(maps, "max-udp-size", &obj);
1415	INSIST(result == ISC_R_SUCCESS);
1416	udpsize = cfg_obj_asuint32(obj);
1417	if (udpsize < 512)
1418		udpsize = 512;
1419	if (udpsize > 4096)
1420		udpsize = 4096;
1421	view->maxudp = udpsize;
1422
1423	/*
1424	 * Set supported DNSSEC algorithms.
1425	 */
1426	dns_resolver_reset_algorithms(view->resolver);
1427	disabled = NULL;
1428	(void)ns_config_get(maps, "disable-algorithms", &disabled);
1429	if (disabled != NULL) {
1430		for (element = cfg_list_first(disabled);
1431		     element != NULL;
1432		     element = cfg_list_next(element))
1433			CHECK(disable_algorithms(cfg_listelt_value(element),
1434						 view->resolver));
1435	}
1436
1437	/*
1438	 * A global or view "forwarders" option, if present,
1439	 * creates an entry for "." in the forwarding table.
1440	 */
1441	forwardtype = NULL;
1442	forwarders = NULL;
1443	(void)ns_config_get(maps, "forward", &forwardtype);
1444	(void)ns_config_get(maps, "forwarders", &forwarders);
1445	if (forwarders != NULL)
1446		CHECK(configure_forward(config, view, dns_rootname,
1447					forwarders, forwardtype));
1448
1449	/*
1450	 * Dual Stack Servers.
1451	 */
1452	alternates = NULL;
1453	(void)ns_config_get(maps, "dual-stack-servers", &alternates);
1454	if (alternates != NULL)
1455		CHECK(configure_alternates(config, view, alternates));
1456
1457	/*
1458	 * We have default hints for class IN if we need them.
1459	 */
1460	if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
1461		dns_view_sethints(view, ns_g_server->in_roothints);
1462
1463	/*
1464	 * If we still have no hints, this is a non-IN view with no
1465	 * "hints zone" configured.  Issue a warning, except if this
1466	 * is a root server.  Root servers never need to consult
1467	 * their hints, so it's no point requiring users to configure
1468	 * them.
1469	 */
1470	if (view->hints == NULL) {
1471		dns_zone_t *rootzone = NULL;
1472		(void)dns_view_findzone(view, dns_rootname, &rootzone);
1473		if (rootzone != NULL) {
1474			dns_zone_detach(&rootzone);
1475			need_hints = ISC_FALSE;
1476		}
1477		if (need_hints)
1478			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1479				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1480				      "no root hints for view '%s'",
1481				      view->name);
1482	}
1483
1484	/*
1485	 * Configure the view's TSIG keys.
1486	 */
1487	ring = NULL;
1488	CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
1489	dns_view_setkeyring(view, ring);
1490
1491	/*
1492	 * Configure the view's peer list.
1493	 */
1494	{
1495		const cfg_obj_t *peers = NULL;
1496		const cfg_listelt_t *element;
1497		dns_peerlist_t *newpeers = NULL;
1498
1499		(void)ns_config_get(cfgmaps, "server", &peers);
1500		CHECK(dns_peerlist_new(mctx, &newpeers));
1501		for (element = cfg_list_first(peers);
1502		     element != NULL;
1503		     element = cfg_list_next(element))
1504		{
1505			const cfg_obj_t *cpeer = cfg_listelt_value(element);
1506			dns_peer_t *peer;
1507
1508			CHECK(configure_peer(cpeer, mctx, &peer));
1509			dns_peerlist_addpeer(newpeers, peer);
1510			dns_peer_detach(&peer);
1511		}
1512		dns_peerlist_detach(&view->peers);
1513		view->peers = newpeers; /* Transfer ownership. */
1514	}
1515
1516	/*
1517	 *	Configure the views rrset-order.
1518	 */
1519	{
1520		const cfg_obj_t *rrsetorder = NULL;
1521		const cfg_listelt_t *element;
1522
1523		(void)ns_config_get(maps, "rrset-order", &rrsetorder);
1524		CHECK(dns_order_create(mctx, &order));
1525		for (element = cfg_list_first(rrsetorder);
1526		     element != NULL;
1527		     element = cfg_list_next(element))
1528		{
1529			const cfg_obj_t *ent = cfg_listelt_value(element);
1530
1531			CHECK(configure_order(order, ent));
1532		}
1533		if (view->order != NULL)
1534			dns_order_detach(&view->order);
1535		dns_order_attach(order, &view->order);
1536		dns_order_detach(&order);
1537	}
1538	/*
1539	 * Copy the aclenv object.
1540	 */
1541	dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
1542
1543	/*
1544	 * Configure the "match-clients" and "match-destinations" ACL.
1545	 */
1546	CHECK(configure_view_acl(vconfig, config, "match-clients", actx,
1547				 ns_g_mctx, &view->matchclients));
1548	CHECK(configure_view_acl(vconfig, config, "match-destinations", actx,
1549				 ns_g_mctx, &view->matchdestinations));
1550
1551	/*
1552	 * Configure the "match-recursive-only" option.
1553	 */
1554	obj = NULL;
1555	(void)ns_config_get(maps, "match-recursive-only", &obj);
1556	if (obj != NULL && cfg_obj_asboolean(obj))
1557		view->matchrecursiveonly = ISC_TRUE;
1558	else
1559		view->matchrecursiveonly = ISC_FALSE;
1560
1561	/*
1562	 * Configure other configurable data.
1563	 */
1564	obj = NULL;
1565	result = ns_config_get(maps, "recursion", &obj);
1566	INSIST(result == ISC_R_SUCCESS);
1567	view->recursion = cfg_obj_asboolean(obj);
1568
1569	obj = NULL;
1570	result = ns_config_get(maps, "auth-nxdomain", &obj);
1571	INSIST(result == ISC_R_SUCCESS);
1572	view->auth_nxdomain = cfg_obj_asboolean(obj);
1573
1574	obj = NULL;
1575	result = ns_config_get(maps, "minimal-responses", &obj);
1576	INSIST(result == ISC_R_SUCCESS);
1577	view->minimalresponses = cfg_obj_asboolean(obj);
1578
1579	obj = NULL;
1580	result = ns_config_get(maps, "transfer-format", &obj);
1581	INSIST(result == ISC_R_SUCCESS);
1582	str = cfg_obj_asstring(obj);
1583	if (strcasecmp(str, "many-answers") == 0)
1584		view->transfer_format = dns_many_answers;
1585	else if (strcasecmp(str, "one-answer") == 0)
1586		view->transfer_format = dns_one_answer;
1587	else
1588		INSIST(0);
1589
1590	/*
1591	 * Set sources where additional data and CNAME/DNAME
1592	 * targets for authoritative answers may be found.
1593	 */
1594	obj = NULL;
1595	result = ns_config_get(maps, "additional-from-auth", &obj);
1596	INSIST(result == ISC_R_SUCCESS);
1597	view->additionalfromauth = cfg_obj_asboolean(obj);
1598	if (view->recursion && ! view->additionalfromauth) {
1599		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1600			    "'additional-from-auth no' is only supported "
1601			    "with 'recursion no'");
1602		view->additionalfromauth = ISC_TRUE;
1603	}
1604
1605	obj = NULL;
1606	result = ns_config_get(maps, "additional-from-cache", &obj);
1607	INSIST(result == ISC_R_SUCCESS);
1608	view->additionalfromcache = cfg_obj_asboolean(obj);
1609	if (view->recursion && ! view->additionalfromcache) {
1610		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1611			    "'additional-from-cache no' is only supported "
1612			    "with 'recursion no'");
1613		view->additionalfromcache = ISC_TRUE;
1614	}
1615
1616	/*
1617	 * Set "allow-query-cache", "allow-query-cache-on",
1618	 * "allow-recursion", and "allow-recursion-on" acls if
1619	 * configured in named.conf.
1620	 */
1621	CHECK(configure_view_acl(vconfig, config, "allow-query-cache",
1622				 actx, ns_g_mctx, &view->cacheacl));
1623	CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on",
1624				 actx, ns_g_mctx, &view->cacheonacl));
1625	if (view->cacheonacl == NULL)
1626		CHECK(configure_view_acl(NULL, ns_g_config,
1627					 "allow-query-cache-on", actx,
1628					 ns_g_mctx, &view->cacheonacl));
1629	if (strcmp(view->name, "_bind") != 0) {
1630		CHECK(configure_view_acl(vconfig, config, "allow-recursion",
1631					 actx, ns_g_mctx,
1632					 &view->recursionacl));
1633		CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
1634					 actx, ns_g_mctx,
1635					 &view->recursiononacl));
1636	}
1637
1638	/*
1639	 * "allow-query-cache" inherits from "allow-recursion" if set,
1640	 * otherwise from "allow-query" if set.
1641	 * "allow-recursion" inherits from "allow-query-cache" if set,
1642	 * otherwise from "allow-query" if set.
1643	 */
1644	if (view->cacheacl == NULL && view->recursionacl != NULL)
1645		dns_acl_attach(view->recursionacl, &view->cacheacl);
1646	if (view->cacheacl == NULL && view->recursion)
1647		CHECK(configure_view_acl(vconfig, config, "allow-query",
1648					 actx, ns_g_mctx, &view->cacheacl));
1649	if (view->recursion &&
1650	    view->recursionacl == NULL && view->cacheacl != NULL)
1651		dns_acl_attach(view->cacheacl, &view->recursionacl);
1652
1653	/*
1654	 * Set default "allow-recursion", "allow-recursion-on" and
1655	 * "allow-query-cache" acls.
1656	 */
1657	if (view->recursionacl == NULL && view->recursion)
1658		CHECK(configure_view_acl(NULL, ns_g_config,
1659					 "allow-recursion",
1660					 actx, ns_g_mctx,
1661					 &view->recursionacl));
1662	if (view->recursiononacl == NULL && view->recursion)
1663		CHECK(configure_view_acl(NULL, ns_g_config,
1664					 "allow-recursion-on",
1665					 actx, ns_g_mctx,
1666					 &view->recursiononacl));
1667	if (view->cacheacl == NULL) {
1668		if (view->recursion)
1669			CHECK(configure_view_acl(NULL, ns_g_config,
1670						 "allow-query-cache", actx,
1671						 ns_g_mctx, &view->cacheacl));
1672		else
1673			CHECK(dns_acl_none(ns_g_mctx, &view->cacheacl));
1674	}
1675
1676	/*
1677	 * Configure sortlist, if set
1678	 */
1679	CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
1680				      &view->sortlist));
1681
1682	/*
1683	 * Configure default allow-transfer, allow-notify, allow-update
1684	 * and allow-update-forwarding ACLs, if set, so they can be
1685	 * inherited by zones.
1686	 */
1687	if (view->notifyacl == NULL)
1688		CHECK(configure_view_acl(NULL, ns_g_config,
1689					 "allow-notify", actx,
1690					 ns_g_mctx, &view->notifyacl));
1691	if (view->transferacl == NULL)
1692		CHECK(configure_view_acl(NULL, ns_g_config,
1693					 "allow-transfer", actx,
1694					 ns_g_mctx, &view->transferacl));
1695	if (view->updateacl == NULL)
1696		CHECK(configure_view_acl(NULL, ns_g_config,
1697					 "allow-update", actx,
1698					 ns_g_mctx, &view->updateacl));
1699	if (view->upfwdacl == NULL)
1700		CHECK(configure_view_acl(NULL, ns_g_config,
1701					 "allow-update-forwarding", actx,
1702					 ns_g_mctx, &view->upfwdacl));
1703
1704	obj = NULL;
1705	result = ns_config_get(maps, "request-ixfr", &obj);
1706	INSIST(result == ISC_R_SUCCESS);
1707	view->requestixfr = cfg_obj_asboolean(obj);
1708
1709	obj = NULL;
1710	result = ns_config_get(maps, "provide-ixfr", &obj);
1711	INSIST(result == ISC_R_SUCCESS);
1712	view->provideixfr = cfg_obj_asboolean(obj);
1713
1714	obj = NULL;
1715	result = ns_config_get(maps, "request-nsid", &obj);
1716	INSIST(result == ISC_R_SUCCESS);
1717	view->requestnsid = cfg_obj_asboolean(obj);
1718
1719	obj = NULL;
1720	result = ns_config_get(maps, "max-clients-per-query", &obj);
1721	INSIST(result == ISC_R_SUCCESS);
1722	max_clients_per_query = cfg_obj_asuint32(obj);
1723
1724	obj = NULL;
1725	result = ns_config_get(maps, "clients-per-query", &obj);
1726	INSIST(result == ISC_R_SUCCESS);
1727	dns_resolver_setclientsperquery(view->resolver,
1728					cfg_obj_asuint32(obj),
1729					max_clients_per_query);
1730
1731	obj = NULL;
1732	result = ns_config_get(maps, "dnssec-enable", &obj);
1733	INSIST(result == ISC_R_SUCCESS);
1734	view->enablednssec = cfg_obj_asboolean(obj);
1735
1736	obj = NULL;
1737	result = ns_config_get(maps, "dnssec-lookaside", &obj);
1738	if (result == ISC_R_SUCCESS) {
1739		for (element = cfg_list_first(obj);
1740		     element != NULL;
1741		     element = cfg_list_next(element))
1742		{
1743			const char *str;
1744			isc_buffer_t b;
1745			dns_name_t *dlv;
1746
1747			obj = cfg_listelt_value(element);
1748#if 0
1749			dns_fixedname_t fixed;
1750			dns_name_t *name;
1751
1752			/*
1753			 * When we support multiple dnssec-lookaside
1754			 * entries this is how to find the domain to be
1755			 * checked. XXXMPA
1756			 */
1757			dns_fixedname_init(&fixed);
1758			name = dns_fixedname_name(&fixed);
1759			str = cfg_obj_asstring(cfg_tuple_get(obj,
1760							     "domain"));
1761			isc_buffer_init(&b, str, strlen(str));
1762			isc_buffer_add(&b, strlen(str));
1763			CHECK(dns_name_fromtext(name, &b, dns_rootname,
1764						ISC_TRUE, NULL));
1765#endif
1766			str = cfg_obj_asstring(cfg_tuple_get(obj,
1767							     "trust-anchor"));
1768			isc_buffer_init(&b, str, strlen(str));
1769			isc_buffer_add(&b, strlen(str));
1770			dlv = dns_fixedname_name(&view->dlv_fixed);
1771			CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
1772						ISC_TRUE, NULL));
1773			view->dlv = dns_fixedname_name(&view->dlv_fixed);
1774		}
1775	} else
1776		view->dlv = NULL;
1777
1778	/*
1779	 * For now, there is only one kind of trusted keys, the
1780	 * "security roots".
1781	 */
1782	CHECK(configure_view_dnsseckeys(vconfig, config, mctx,
1783					&view->secroots));
1784	dns_resolver_resetmustbesecure(view->resolver);
1785	obj = NULL;
1786	result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
1787	if (result == ISC_R_SUCCESS)
1788		CHECK(mustbesecure(obj, view->resolver));
1789
1790	obj = NULL;
1791	result = ns_config_get(maps, "preferred-glue", &obj);
1792	if (result == ISC_R_SUCCESS) {
1793		str = cfg_obj_asstring(obj);
1794		if (strcasecmp(str, "a") == 0)
1795			view->preferred_glue = dns_rdatatype_a;
1796		else if (strcasecmp(str, "aaaa") == 0)
1797			view->preferred_glue = dns_rdatatype_aaaa;
1798		else
1799			view->preferred_glue = 0;
1800	} else
1801		view->preferred_glue = 0;
1802
1803	obj = NULL;
1804	result = ns_config_get(maps, "root-delegation-only", &obj);
1805	if (result == ISC_R_SUCCESS) {
1806		dns_view_setrootdelonly(view, ISC_TRUE);
1807		if (!cfg_obj_isvoid(obj)) {
1808			dns_fixedname_t fixed;
1809			dns_name_t *name;
1810			isc_buffer_t b;
1811			const char *str;
1812			const cfg_obj_t *exclude;
1813
1814			dns_fixedname_init(&fixed);
1815			name = dns_fixedname_name(&fixed);
1816			for (element = cfg_list_first(obj);
1817			     element != NULL;
1818			     element = cfg_list_next(element)) {
1819				exclude = cfg_listelt_value(element);
1820				str = cfg_obj_asstring(exclude);
1821				isc_buffer_init(&b, str, strlen(str));
1822				isc_buffer_add(&b, strlen(str));
1823				CHECK(dns_name_fromtext(name, &b, dns_rootname,
1824							ISC_FALSE, NULL));
1825				CHECK(dns_view_excludedelegationonly(view,
1826								     name));
1827			}
1828		}
1829	} else
1830		dns_view_setrootdelonly(view, ISC_FALSE);
1831
1832	/*
1833	 * Setup automatic empty zones.  If recursion is off then
1834	 * they are disabled by default.
1835	 */
1836	obj = NULL;
1837	(void)ns_config_get(maps, "empty-zones-enable", &obj);
1838	(void)ns_config_get(maps, "disable-empty-zone", &disablelist);
1839	if (obj == NULL && disablelist == NULL &&
1840	    view->rdclass == dns_rdataclass_in) {
1841		rfc1918 = ISC_FALSE;
1842		empty_zones_enable = view->recursion;
1843	} else if (view->rdclass == dns_rdataclass_in) {
1844		rfc1918 = ISC_TRUE;
1845		if (obj != NULL)
1846			empty_zones_enable = cfg_obj_asboolean(obj);
1847		else
1848			empty_zones_enable = view->recursion;
1849	} else {
1850		rfc1918 = ISC_FALSE;
1851		empty_zones_enable = ISC_FALSE;
1852	}
1853	if (empty_zones_enable) {
1854		const char *empty;
1855		int empty_zone = 0;
1856		dns_fixedname_t fixed;
1857		dns_name_t *name;
1858		isc_buffer_t buffer;
1859		const char *str;
1860		char server[DNS_NAME_FORMATSIZE + 1];
1861		char contact[DNS_NAME_FORMATSIZE + 1];
1862		isc_boolean_t logit;
1863		const char *empty_dbtype[4] =
1864				    { "_builtin", "empty", NULL, NULL };
1865		int empty_dbtypec = 4;
1866		isc_boolean_t zonestats_on;
1867
1868		dns_fixedname_init(&fixed);
1869		name = dns_fixedname_name(&fixed);
1870
1871		obj = NULL;
1872		result = ns_config_get(maps, "empty-server", &obj);
1873		if (result == ISC_R_SUCCESS) {
1874			str = cfg_obj_asstring(obj);
1875			isc_buffer_init(&buffer, str, strlen(str));
1876			isc_buffer_add(&buffer, strlen(str));
1877			CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1878						ISC_FALSE, NULL));
1879			isc_buffer_init(&buffer, server, sizeof(server) - 1);
1880			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
1881			server[isc_buffer_usedlength(&buffer)] = 0;
1882			empty_dbtype[2] = server;
1883		} else
1884			empty_dbtype[2] = "@";
1885
1886		obj = NULL;
1887		result = ns_config_get(maps, "empty-contact", &obj);
1888		if (result == ISC_R_SUCCESS) {
1889			str = cfg_obj_asstring(obj);
1890			isc_buffer_init(&buffer, str, strlen(str));
1891			isc_buffer_add(&buffer, strlen(str));
1892			CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1893						ISC_FALSE, NULL));
1894			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
1895			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
1896			contact[isc_buffer_usedlength(&buffer)] = 0;
1897			empty_dbtype[3] = contact;
1898		} else
1899			empty_dbtype[3] = ".";
1900
1901		obj = NULL;
1902		result = ns_config_get(maps, "zone-statistics", &obj);
1903		INSIST(result == ISC_R_SUCCESS);
1904		zonestats_on = cfg_obj_asboolean(obj);
1905
1906		logit = ISC_TRUE;
1907		for (empty = empty_zones[empty_zone].zone;
1908		     empty != NULL;
1909		     empty = empty_zones[++empty_zone].zone)
1910		{
1911			dns_forwarders_t *forwarders = NULL;
1912			dns_view_t *pview = NULL;
1913
1914			isc_buffer_init(&buffer, empty, strlen(empty));
1915			isc_buffer_add(&buffer, strlen(empty));
1916			/*
1917			 * Look for zone on drop list.
1918			 */
1919			CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1920						ISC_FALSE, NULL));
1921			if (disablelist != NULL &&
1922			    on_disable_list(disablelist, name))
1923				continue;
1924
1925			/*
1926			 * This zone already exists.
1927			 */
1928			(void)dns_view_findzone(view, name, &zone);
1929			if (zone != NULL) {
1930				CHECK(setquerystats(zone, mctx, zonestats_on));
1931				dns_zone_detach(&zone);
1932				continue;
1933			}
1934
1935			/*
1936			 * If we would forward this name don't add a
1937			 * empty zone for it.
1938			 */
1939			result = dns_fwdtable_find(view->fwdtable, name,
1940						   &forwarders);
1941			if (result == ISC_R_SUCCESS &&
1942			    forwarders->fwdpolicy == dns_fwdpolicy_only)
1943				continue;
1944
1945			if (!rfc1918 && empty_zones[empty_zone].rfc1918) {
1946				if (logit) {
1947					isc_log_write(ns_g_lctx,
1948						      NS_LOGCATEGORY_GENERAL,
1949						      NS_LOGMODULE_SERVER,
1950						      ISC_LOG_WARNING,
1951						      "Warning%s%s: "
1952						      "'empty-zones-enable/"
1953						      "disable-empty-zone' "
1954						      "not set: disabling "
1955						      "RFC 1918 empty zones",
1956						      sep, viewname);
1957					logit = ISC_FALSE;
1958				}
1959				continue;
1960			}
1961
1962			/*
1963			 * See if we can re-use a existing zone.
1964			 */
1965			result = dns_viewlist_find(&ns_g_server->viewlist,
1966						   view->name, view->rdclass,
1967						   &pview);
1968			if (result != ISC_R_NOTFOUND &&
1969			    result != ISC_R_SUCCESS)
1970				goto cleanup;
1971
1972			if (pview != NULL) {
1973				(void)dns_view_findzone(pview, name, &zone);
1974				dns_view_detach(&pview);
1975				if (zone != NULL)
1976					check_dbtype(&zone, empty_dbtypec,
1977						     empty_dbtype, mctx);
1978				if (zone != NULL) {
1979					dns_zone_setview(zone, view);
1980					CHECK(dns_view_addzone(view, zone));
1981					CHECK(setquerystats(zone, mctx,
1982							    zonestats_on));
1983					dns_zone_detach(&zone);
1984					continue;
1985				}
1986			}
1987
1988			CHECK(dns_zone_create(&zone, mctx));
1989			CHECK(dns_zone_setorigin(zone, name));
1990			dns_zone_setview(zone, view);
1991			CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1992			dns_zone_setclass(zone, view->rdclass);
1993			dns_zone_settype(zone, dns_zone_master);
1994			dns_zone_setstats(zone, ns_g_server->zonestats);
1995			CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
1996						 empty_dbtype));
1997			if (view->queryacl != NULL)
1998				dns_zone_setqueryacl(zone, view->queryacl);
1999			if (view->queryonacl != NULL)
2000				dns_zone_setqueryonacl(zone, view->queryonacl);
2001			dns_zone_setdialup(zone, dns_dialuptype_no);
2002			dns_zone_setnotifytype(zone, dns_notifytype_no);
2003			dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS,
2004					   ISC_TRUE);
2005			CHECK(setquerystats(zone, mctx, zonestats_on));
2006			CHECK(dns_view_addzone(view, zone));
2007			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2008				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2009				      "automatic empty zone%s%s: %s",
2010				      sep, viewname,  empty);
2011			dns_zone_detach(&zone);
2012		}
2013	}
2014
2015	result = ISC_R_SUCCESS;
2016
2017 cleanup:
2018	if (zone != NULL)
2019		dns_zone_detach(&zone);
2020	if (dispatch4 != NULL)
2021		dns_dispatch_detach(&dispatch4);
2022	if (dispatch6 != NULL)
2023		dns_dispatch_detach(&dispatch6);
2024	if (resstats != NULL)
2025		isc_stats_detach(&resstats);
2026	if (resquerystats != NULL)
2027		dns_stats_detach(&resquerystats);
2028	if (order != NULL)
2029		dns_order_detach(&order);
2030	if (cmctx != NULL)
2031		isc_mem_detach(&cmctx);
2032
2033	if (cache != NULL)
2034		dns_cache_detach(&cache);
2035
2036	return (result);
2037}
2038
2039static isc_result_t
2040configure_hints(dns_view_t *view, const char *filename) {
2041	isc_result_t result;
2042	dns_db_t *db;
2043
2044	db = NULL;
2045	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
2046	if (result == ISC_R_SUCCESS) {
2047		dns_view_sethints(view, db);
2048		dns_db_detach(&db);
2049	}
2050
2051	return (result);
2052}
2053
2054static isc_result_t
2055configure_alternates(const cfg_obj_t *config, dns_view_t *view,
2056		     const cfg_obj_t *alternates)
2057{
2058	const cfg_obj_t *portobj;
2059	const cfg_obj_t *addresses;
2060	const cfg_listelt_t *element;
2061	isc_result_t result = ISC_R_SUCCESS;
2062	in_port_t port;
2063
2064	/*
2065	 * Determine which port to send requests to.
2066	 */
2067	if (ns_g_lwresdonly && ns_g_port != 0)
2068		port = ns_g_port;
2069	else
2070		CHECKM(ns_config_getport(config, &port), "port");
2071
2072	if (alternates != NULL) {
2073		portobj = cfg_tuple_get(alternates, "port");
2074		if (cfg_obj_isuint32(portobj)) {
2075			isc_uint32_t val = cfg_obj_asuint32(portobj);
2076			if (val > ISC_UINT16_MAX) {
2077				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
2078					    "port '%u' out of range", val);
2079				return (ISC_R_RANGE);
2080			}
2081			port = (in_port_t) val;
2082		}
2083	}
2084
2085	addresses = NULL;
2086	if (alternates != NULL)
2087		addresses = cfg_tuple_get(alternates, "addresses");
2088
2089	for (element = cfg_list_first(addresses);
2090	     element != NULL;
2091	     element = cfg_list_next(element))
2092	{
2093		const cfg_obj_t *alternate = cfg_listelt_value(element);
2094		isc_sockaddr_t sa;
2095
2096		if (!cfg_obj_issockaddr(alternate)) {
2097			dns_fixedname_t fixed;
2098			dns_name_t *name;
2099			const char *str = cfg_obj_asstring(cfg_tuple_get(
2100							   alternate, "name"));
2101			isc_buffer_t buffer;
2102			in_port_t myport = port;
2103
2104			isc_buffer_init(&buffer, str, strlen(str));
2105			isc_buffer_add(&buffer, strlen(str));
2106			dns_fixedname_init(&fixed);
2107			name = dns_fixedname_name(&fixed);
2108			CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
2109						ISC_FALSE, NULL));
2110
2111			portobj = cfg_tuple_get(alternate, "port");
2112			if (cfg_obj_isuint32(portobj)) {
2113				isc_uint32_t val = cfg_obj_asuint32(portobj);
2114				if (val > ISC_UINT16_MAX) {
2115					cfg_obj_log(portobj, ns_g_lctx,
2116						    ISC_LOG_ERROR,
2117						    "port '%u' out of range",
2118						     val);
2119					return (ISC_R_RANGE);
2120				}
2121				myport = (in_port_t) val;
2122			}
2123			CHECK(dns_resolver_addalternate(view->resolver, NULL,
2124							name, myport));
2125			continue;
2126		}
2127
2128		sa = *cfg_obj_assockaddr(alternate);
2129		if (isc_sockaddr_getport(&sa) == 0)
2130			isc_sockaddr_setport(&sa, port);
2131		CHECK(dns_resolver_addalternate(view->resolver, &sa,
2132						NULL, 0));
2133	}
2134
2135 cleanup:
2136	return (result);
2137}
2138
2139static isc_result_t
2140configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
2141		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
2142{
2143	const cfg_obj_t *portobj;
2144	const cfg_obj_t *faddresses;
2145	const cfg_listelt_t *element;
2146	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
2147	isc_sockaddrlist_t addresses;
2148	isc_sockaddr_t *sa;
2149	isc_result_t result;
2150	in_port_t port;
2151
2152	ISC_LIST_INIT(addresses);
2153
2154	/*
2155	 * Determine which port to send forwarded requests to.
2156	 */
2157	if (ns_g_lwresdonly && ns_g_port != 0)
2158		port = ns_g_port;
2159	else
2160		CHECKM(ns_config_getport(config, &port), "port");
2161
2162	if (forwarders != NULL) {
2163		portobj = cfg_tuple_get(forwarders, "port");
2164		if (cfg_obj_isuint32(portobj)) {
2165			isc_uint32_t val = cfg_obj_asuint32(portobj);
2166			if (val > ISC_UINT16_MAX) {
2167				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
2168					    "port '%u' out of range", val);
2169				return (ISC_R_RANGE);
2170			}
2171			port = (in_port_t) val;
2172		}
2173	}
2174
2175	faddresses = NULL;
2176	if (forwarders != NULL)
2177		faddresses = cfg_tuple_get(forwarders, "addresses");
2178
2179	for (element = cfg_list_first(faddresses);
2180	     element != NULL;
2181	     element = cfg_list_next(element))
2182	{
2183		const cfg_obj_t *forwarder = cfg_listelt_value(element);
2184		sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
2185		if (sa == NULL) {
2186			result = ISC_R_NOMEMORY;
2187			goto cleanup;
2188		}
2189		*sa = *cfg_obj_assockaddr(forwarder);
2190		if (isc_sockaddr_getport(sa) == 0)
2191			isc_sockaddr_setport(sa, port);
2192		ISC_LINK_INIT(sa, link);
2193		ISC_LIST_APPEND(addresses, sa, link);
2194	}
2195
2196	if (ISC_LIST_EMPTY(addresses)) {
2197		if (forwardtype != NULL)
2198			cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
2199				    "no forwarders seen; disabling "
2200				    "forwarding");
2201		fwdpolicy = dns_fwdpolicy_none;
2202	} else {
2203		if (forwardtype == NULL)
2204			fwdpolicy = dns_fwdpolicy_first;
2205		else {
2206			const char *forwardstr = cfg_obj_asstring(forwardtype);
2207			if (strcasecmp(forwardstr, "first") == 0)
2208				fwdpolicy = dns_fwdpolicy_first;
2209			else if (strcasecmp(forwardstr, "only") == 0)
2210				fwdpolicy = dns_fwdpolicy_only;
2211			else
2212				INSIST(0);
2213		}
2214	}
2215
2216	result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
2217				  fwdpolicy);
2218	if (result != ISC_R_SUCCESS) {
2219		char namebuf[DNS_NAME_FORMATSIZE];
2220		dns_name_format(origin, namebuf, sizeof(namebuf));
2221		cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
2222			    "could not set up forwarding for domain '%s': %s",
2223			    namebuf, isc_result_totext(result));
2224		goto cleanup;
2225	}
2226
2227	result = ISC_R_SUCCESS;
2228
2229 cleanup:
2230
2231	while (!ISC_LIST_EMPTY(addresses)) {
2232		sa = ISC_LIST_HEAD(addresses);
2233		ISC_LIST_UNLINK(addresses, sa, link);
2234		isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
2235	}
2236
2237	return (result);
2238}
2239
2240/*
2241 * Create a new view and add it to the list.
2242 *
2243 * If 'vconfig' is NULL, create the default view.
2244 *
2245 * The view created is attached to '*viewp'.
2246 */
2247static isc_result_t
2248create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
2249	    dns_view_t **viewp)
2250{
2251	isc_result_t result;
2252	const char *viewname;
2253	dns_rdataclass_t viewclass;
2254	dns_view_t *view = NULL;
2255
2256	if (vconfig != NULL) {
2257		const cfg_obj_t *classobj = NULL;
2258
2259		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
2260		classobj = cfg_tuple_get(vconfig, "class");
2261		result = ns_config_getclass(classobj, dns_rdataclass_in,
2262					    &viewclass);
2263	} else {
2264		viewname = "_default";
2265		viewclass = dns_rdataclass_in;
2266	}
2267	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
2268	if (result == ISC_R_SUCCESS)
2269		return (ISC_R_EXISTS);
2270	if (result != ISC_R_NOTFOUND)
2271		return (result);
2272	INSIST(view == NULL);
2273
2274	result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
2275	if (result != ISC_R_SUCCESS)
2276		return (result);
2277
2278	ISC_LIST_APPEND(*viewlist, view, link);
2279	dns_view_attach(view, viewp);
2280	return (ISC_R_SUCCESS);
2281}
2282
2283/*
2284 * Configure or reconfigure a zone.
2285 */
2286static isc_result_t
2287configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
2288	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
2289	       cfg_aclconfctx_t *aclconf)
2290{
2291	dns_view_t *pview = NULL;	/* Production view */
2292	dns_zone_t *zone = NULL;	/* New or reused zone */
2293	dns_zone_t *dupzone = NULL;
2294	const cfg_obj_t *options = NULL;
2295	const cfg_obj_t *zoptions = NULL;
2296	const cfg_obj_t *typeobj = NULL;
2297	const cfg_obj_t *forwarders = NULL;
2298	const cfg_obj_t *forwardtype = NULL;
2299	const cfg_obj_t *only = NULL;
2300	isc_result_t result;
2301	isc_result_t tresult;
2302	isc_buffer_t buffer;
2303	dns_fixedname_t fixorigin;
2304	dns_name_t *origin;
2305	const char *zname;
2306	dns_rdataclass_t zclass;
2307	const char *ztypestr;
2308
2309	options = NULL;
2310	(void)cfg_map_get(config, "options", &options);
2311
2312	zoptions = cfg_tuple_get(zconfig, "options");
2313
2314	/*
2315	 * Get the zone origin as a dns_name_t.
2316	 */
2317	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
2318	isc_buffer_init(&buffer, zname, strlen(zname));
2319	isc_buffer_add(&buffer, strlen(zname));
2320	dns_fixedname_init(&fixorigin);
2321	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
2322				&buffer, dns_rootname, ISC_FALSE, NULL));
2323	origin = dns_fixedname_name(&fixorigin);
2324
2325	CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
2326				 view->rdclass, &zclass));
2327	if (zclass != view->rdclass) {
2328		const char *vname = NULL;
2329		if (vconfig != NULL)
2330			vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
2331							       "name"));
2332		else
2333			vname = "<default view>";
2334
2335		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2336			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2337			      "zone '%s': wrong class for view '%s'",
2338			      zname, vname);
2339		result = ISC_R_FAILURE;
2340		goto cleanup;
2341	}
2342
2343	(void)cfg_map_get(zoptions, "type", &typeobj);
2344	if (typeobj == NULL) {
2345		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
2346			    "zone '%s' 'type' not specified", zname);
2347		return (ISC_R_FAILURE);
2348	}
2349	ztypestr = cfg_obj_asstring(typeobj);
2350
2351	/*
2352	 * "hints zones" aren't zones.  If we've got one,
2353	 * configure it and return.
2354	 */
2355	if (strcasecmp(ztypestr, "hint") == 0) {
2356		const cfg_obj_t *fileobj = NULL;
2357		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
2358			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2359				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2360				      "zone '%s': 'file' not specified",
2361				      zname);
2362			result = ISC_R_FAILURE;
2363			goto cleanup;
2364		}
2365		if (dns_name_equal(origin, dns_rootname)) {
2366			const char *hintsfile = cfg_obj_asstring(fileobj);
2367
2368			result = configure_hints(view, hintsfile);
2369			if (result != ISC_R_SUCCESS) {
2370				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2371					      NS_LOGMODULE_SERVER,
2372					      ISC_LOG_ERROR,
2373					      "could not configure root hints "
2374					      "from '%s': %s", hintsfile,
2375					      isc_result_totext(result));
2376				goto cleanup;
2377			}
2378			/*
2379			 * Hint zones may also refer to delegation only points.
2380			 */
2381			only = NULL;
2382			tresult = cfg_map_get(zoptions, "delegation-only",
2383					      &only);
2384			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
2385				CHECK(dns_view_adddelegationonly(view, origin));
2386		} else {
2387			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2388				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2389				      "ignoring non-root hint zone '%s'",
2390				      zname);
2391			result = ISC_R_SUCCESS;
2392		}
2393		/* Skip ordinary zone processing. */
2394		goto cleanup;
2395	}
2396
2397	/*
2398	 * "forward zones" aren't zones either.  Translate this syntax into
2399	 * the appropriate selective forwarding configuration and return.
2400	 */
2401	if (strcasecmp(ztypestr, "forward") == 0) {
2402		forwardtype = NULL;
2403		forwarders = NULL;
2404
2405		(void)cfg_map_get(zoptions, "forward", &forwardtype);
2406		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
2407		result = configure_forward(config, view, origin, forwarders,
2408					   forwardtype);
2409		goto cleanup;
2410	}
2411
2412	/*
2413	 * "delegation-only zones" aren't zones either.
2414	 */
2415	if (strcasecmp(ztypestr, "delegation-only") == 0) {
2416		result = dns_view_adddelegationonly(view, origin);
2417		goto cleanup;
2418	}
2419
2420	/*
2421	 * Check for duplicates in the new zone table.
2422	 */
2423	result = dns_view_findzone(view, origin, &dupzone);
2424	if (result == ISC_R_SUCCESS) {
2425		/*
2426		 * We already have this zone!
2427		 */
2428		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
2429			    "zone '%s' already exists", zname);
2430		dns_zone_detach(&dupzone);
2431		result = ISC_R_EXISTS;
2432		goto cleanup;
2433	}
2434	INSIST(dupzone == NULL);
2435
2436	/*
2437	 * See if we can reuse an existing zone.  This is
2438	 * only possible if all of these are true:
2439	 *   - The zone's view exists
2440	 *   - A zone with the right name exists in the view
2441	 *   - The zone is compatible with the config
2442	 *     options (e.g., an existing master zone cannot
2443	 *     be reused if the options specify a slave zone)
2444	 */
2445	result = dns_viewlist_find(&ns_g_server->viewlist,
2446				   view->name, view->rdclass,
2447				   &pview);
2448	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2449		goto cleanup;
2450	if (pview != NULL)
2451		result = dns_view_findzone(pview, origin, &zone);
2452	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2453		goto cleanup;
2454	if (zone != NULL && !ns_zone_reusable(zone, zconfig))
2455		dns_zone_detach(&zone);
2456
2457	if (zone != NULL) {
2458		/*
2459		 * We found a reusable zone.  Make it use the
2460		 * new view.
2461		 */
2462		dns_zone_setview(zone, view);
2463		if (view->acache != NULL)
2464			dns_zone_setacache(zone, view->acache);
2465	} else {
2466		/*
2467		 * We cannot reuse an existing zone, we have
2468		 * to create a new one.
2469		 */
2470		CHECK(dns_zone_create(&zone, mctx));
2471		CHECK(dns_zone_setorigin(zone, origin));
2472		dns_zone_setview(zone, view);
2473		if (view->acache != NULL)
2474			dns_zone_setacache(zone, view->acache);
2475		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
2476		dns_zone_setstats(zone, ns_g_server->zonestats);
2477	}
2478
2479	/*
2480	 * If the zone contains a 'forwarders' statement, configure
2481	 * selective forwarding.
2482	 */
2483	forwarders = NULL;
2484	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
2485	{
2486		forwardtype = NULL;
2487		(void)cfg_map_get(zoptions, "forward", &forwardtype);
2488		CHECK(configure_forward(config, view, origin, forwarders,
2489					forwardtype));
2490	}
2491
2492	/*
2493	 * Stub and forward zones may also refer to delegation only points.
2494	 */
2495	only = NULL;
2496	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
2497	{
2498		if (cfg_obj_asboolean(only))
2499			CHECK(dns_view_adddelegationonly(view, origin));
2500	}
2501
2502	/*
2503	 * Configure the zone.
2504	 */
2505	CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
2506
2507	/*
2508	 * Add the zone to its view in the new view list.
2509	 */
2510	CHECK(dns_view_addzone(view, zone));
2511
2512 cleanup:
2513	if (zone != NULL)
2514		dns_zone_detach(&zone);
2515	if (pview != NULL)
2516		dns_view_detach(&pview);
2517
2518	return (result);
2519}
2520
2521/*
2522 * Configure a single server quota.
2523 */
2524static void
2525configure_server_quota(const cfg_obj_t **maps, const char *name,
2526		       isc_quota_t *quota)
2527{
2528	const cfg_obj_t *obj = NULL;
2529	isc_result_t result;
2530
2531	result = ns_config_get(maps, name, &obj);
2532	INSIST(result == ISC_R_SUCCESS);
2533	isc_quota_max(quota, cfg_obj_asuint32(obj));
2534}
2535
2536/*
2537 * This function is called as soon as the 'directory' statement has been
2538 * parsed.  This can be extended to support other options if necessary.
2539 */
2540static isc_result_t
2541directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
2542	isc_result_t result;
2543	const char *directory;
2544
2545	REQUIRE(strcasecmp("directory", clausename) == 0);
2546
2547	UNUSED(arg);
2548	UNUSED(clausename);
2549
2550	/*
2551	 * Change directory.
2552	 */
2553	directory = cfg_obj_asstring(obj);
2554
2555	if (! isc_file_ischdiridempotent(directory))
2556		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
2557			    "option 'directory' contains relative path '%s'",
2558			    directory);
2559
2560	result = isc_dir_chdir(directory);
2561	if (result != ISC_R_SUCCESS) {
2562		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
2563			    "change directory to '%s' failed: %s",
2564			    directory, isc_result_totext(result));
2565		return (result);
2566	}
2567
2568	return (ISC_R_SUCCESS);
2569}
2570
2571static void
2572scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
2573	isc_boolean_t match_mapped = server->aclenv.match_mapped;
2574
2575	ns_interfacemgr_scan(server->interfacemgr, verbose);
2576	/*
2577	 * Update the "localhost" and "localnets" ACLs to match the
2578	 * current set of network interfaces.
2579	 */
2580	dns_aclenv_copy(&server->aclenv,
2581			ns_interfacemgr_getaclenv(server->interfacemgr));
2582
2583	server->aclenv.match_mapped = match_mapped;
2584}
2585
2586static isc_result_t
2587add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
2588	      isc_boolean_t wcardport_ok)
2589{
2590	ns_listenelt_t *lelt = NULL;
2591	dns_acl_t *src_acl = NULL;
2592	isc_result_t result;
2593	isc_sockaddr_t any_sa6;
2594	isc_netaddr_t netaddr;
2595
2596	REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
2597
2598	isc_sockaddr_any6(&any_sa6);
2599	if (!isc_sockaddr_equal(&any_sa6, addr) &&
2600	    (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
2601		isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
2602
2603		result = dns_acl_create(mctx, 0, &src_acl);
2604		if (result != ISC_R_SUCCESS)
2605			return (result);
2606
2607		result = dns_iptable_addprefix(src_acl->iptable,
2608					       &netaddr, 128, ISC_TRUE);
2609		if (result != ISC_R_SUCCESS)
2610			goto clean;
2611
2612		result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
2613					     src_acl, &lelt);
2614		if (result != ISC_R_SUCCESS)
2615			goto clean;
2616		ISC_LIST_APPEND(list->elts, lelt, link);
2617	}
2618
2619	return (ISC_R_SUCCESS);
2620
2621 clean:
2622	INSIST(lelt == NULL);
2623	dns_acl_detach(&src_acl);
2624
2625	return (result);
2626}
2627
2628/*
2629 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
2630 * to update the listening interfaces accordingly.
2631 * We currently only consider IPv6, because this only affects IPv6 wildcard
2632 * sockets.
2633 */
2634static void
2635adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
2636	isc_result_t result;
2637	ns_listenlist_t *list = NULL;
2638	dns_view_t *view;
2639	dns_zone_t *zone, *next;
2640	isc_sockaddr_t addr, *addrp;
2641
2642	result = ns_listenlist_create(mctx, &list);
2643	if (result != ISC_R_SUCCESS)
2644		return;
2645
2646	for (view = ISC_LIST_HEAD(server->viewlist);
2647	     view != NULL;
2648	     view = ISC_LIST_NEXT(view, link)) {
2649		dns_dispatch_t *dispatch6;
2650
2651		dispatch6 = dns_resolver_dispatchv6(view->resolver);
2652		if (dispatch6 == NULL)
2653			continue;
2654		result = dns_dispatch_getlocaladdress(dispatch6, &addr);
2655		if (result != ISC_R_SUCCESS)
2656			goto fail;
2657
2658		/*
2659		 * We always add non-wildcard address regardless of whether
2660		 * the port is 'any' (the fourth arg is TRUE): if the port is
2661		 * specific, we need to add it since it may conflict with a
2662		 * listening interface; if it's zero, we'll dynamically open
2663		 * query ports, and some of them may override an existing
2664		 * wildcard IPv6 port.
2665		 */
2666		result = add_listenelt(mctx, list, &addr, ISC_TRUE);
2667		if (result != ISC_R_SUCCESS)
2668			goto fail;
2669	}
2670
2671	zone = NULL;
2672	for (result = dns_zone_first(server->zonemgr, &zone);
2673	     result == ISC_R_SUCCESS;
2674	     next = NULL, result = dns_zone_next(zone, &next), zone = next) {
2675		dns_view_t *zoneview;
2676
2677		/*
2678		 * At this point the zone list may contain a stale zone
2679		 * just removed from the configuration.  To see the validity,
2680		 * check if the corresponding view is in our current view list.
2681		 * There may also be old zones that are still in the process
2682		 * of shutting down and have detached from their old view
2683		 * (zoneview == NULL).
2684		 */
2685		zoneview = dns_zone_getview(zone);
2686		if (zoneview == NULL)
2687			continue;
2688		for (view = ISC_LIST_HEAD(server->viewlist);
2689		     view != NULL && view != zoneview;
2690		     view = ISC_LIST_NEXT(view, link))
2691			;
2692		if (view == NULL)
2693			continue;
2694
2695		addrp = dns_zone_getnotifysrc6(zone);
2696		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
2697		if (result != ISC_R_SUCCESS)
2698			goto fail;
2699
2700		addrp = dns_zone_getxfrsource6(zone);
2701		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
2702		if (result != ISC_R_SUCCESS)
2703			goto fail;
2704	}
2705
2706	ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
2707
2708 clean:
2709	ns_listenlist_detach(&list);
2710	return;
2711
2712 fail:
2713	/*
2714	 * Even when we failed the procedure, most of other interfaces
2715	 * should work correctly.  We therefore just warn it.
2716	 */
2717	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2718		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2719		      "could not adjust the listen-on list; "
2720		      "some interfaces may not work");
2721	goto clean;
2722}
2723
2724/*
2725 * This event callback is invoked to do periodic network
2726 * interface scanning.
2727 */
2728static void
2729interface_timer_tick(isc_task_t *task, isc_event_t *event) {
2730	isc_result_t result;
2731	ns_server_t *server = (ns_server_t *) event->ev_arg;
2732	INSIST(task == server->task);
2733	UNUSED(task);
2734	isc_event_free(&event);
2735	/*
2736	 * XXX should scan interfaces unlocked and get exclusive access
2737	 * only to replace ACLs.
2738	 */
2739	result = isc_task_beginexclusive(server->task);
2740	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2741	scan_interfaces(server, ISC_FALSE);
2742	isc_task_endexclusive(server->task);
2743}
2744
2745static void
2746heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
2747	ns_server_t *server = (ns_server_t *) event->ev_arg;
2748	dns_view_t *view;
2749
2750	UNUSED(task);
2751	isc_event_free(&event);
2752	view = ISC_LIST_HEAD(server->viewlist);
2753	while (view != NULL) {
2754		dns_view_dialup(view);
2755		view = ISC_LIST_NEXT(view, link);
2756	}
2757}
2758
2759static void
2760pps_timer_tick(isc_task_t *task, isc_event_t *event) {
2761	static unsigned int oldrequests = 0;
2762	unsigned int requests = ns_client_requests;
2763
2764	UNUSED(task);
2765	isc_event_free(&event);
2766
2767	/*
2768	 * Don't worry about wrapping as the overflow result will be right.
2769	 */
2770	dns_pps = (requests - oldrequests) / 1200;
2771	oldrequests = requests;
2772}
2773
2774/*
2775 * Replace the current value of '*field', a dynamically allocated
2776 * string or NULL, with a dynamically allocated copy of the
2777 * null-terminated string pointed to by 'value', or NULL.
2778 */
2779static isc_result_t
2780setstring(ns_server_t *server, char **field, const char *value) {
2781	char *copy;
2782
2783	if (value != NULL) {
2784		copy = isc_mem_strdup(server->mctx, value);
2785		if (copy == NULL)
2786			return (ISC_R_NOMEMORY);
2787	} else {
2788		copy = NULL;
2789	}
2790
2791	if (*field != NULL)
2792		isc_mem_free(server->mctx, *field);
2793
2794	*field = copy;
2795	return (ISC_R_SUCCESS);
2796}
2797
2798/*
2799 * Replace the current value of '*field', a dynamically allocated
2800 * string or NULL, with another dynamically allocated string
2801 * or NULL if whether 'obj' is a string or void value, respectively.
2802 */
2803static isc_result_t
2804setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
2805	if (cfg_obj_isvoid(obj))
2806		return (setstring(server, field, NULL));
2807	else
2808		return (setstring(server, field, cfg_obj_asstring(obj)));
2809}
2810
2811static void
2812set_limit(const cfg_obj_t **maps, const char *configname,
2813	  const char *description, isc_resource_t resourceid,
2814	  isc_resourcevalue_t defaultvalue)
2815{
2816	const cfg_obj_t *obj = NULL;
2817	const char *resource;
2818	isc_resourcevalue_t value;
2819	isc_result_t result;
2820
2821	if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
2822		return;
2823
2824	if (cfg_obj_isstring(obj)) {
2825		resource = cfg_obj_asstring(obj);
2826		if (strcasecmp(resource, "unlimited") == 0)
2827			value = ISC_RESOURCE_UNLIMITED;
2828		else {
2829			INSIST(strcasecmp(resource, "default") == 0);
2830			value = defaultvalue;
2831		}
2832	} else
2833		value = cfg_obj_asuint64(obj);
2834
2835	result = isc_resource_setlimit(resourceid, value);
2836	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2837		      result == ISC_R_SUCCESS ?
2838			ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
2839		      "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
2840		      description, value, isc_result_totext(result));
2841}
2842
2843#define SETLIMIT(cfgvar, resource, description) \
2844	set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
2845		  ns_g_init ## resource)
2846
2847static void
2848set_limits(const cfg_obj_t **maps) {
2849	SETLIMIT("stacksize", stacksize, "stack size");
2850	SETLIMIT("datasize", datasize, "data size");
2851	SETLIMIT("coresize", coresize, "core size");
2852	SETLIMIT("files", openfiles, "open files");
2853}
2854
2855static void
2856portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
2857		 isc_boolean_t positive)
2858{
2859	const cfg_listelt_t *element;
2860
2861	for (element = cfg_list_first(ports);
2862	     element != NULL;
2863	     element = cfg_list_next(element)) {
2864		const cfg_obj_t *obj = cfg_listelt_value(element);
2865
2866		if (cfg_obj_isuint32(obj)) {
2867			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
2868
2869			if (positive)
2870				isc_portset_add(portset, port);
2871			else
2872				isc_portset_remove(portset, port);
2873		} else {
2874			const cfg_obj_t *obj_loport, *obj_hiport;
2875			in_port_t loport, hiport;
2876
2877			obj_loport = cfg_tuple_get(obj, "loport");
2878			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
2879			obj_hiport = cfg_tuple_get(obj, "hiport");
2880			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
2881
2882			if (positive)
2883				isc_portset_addrange(portset, loport, hiport);
2884			else {
2885				isc_portset_removerange(portset, loport,
2886							hiport);
2887			}
2888		}
2889	}
2890}
2891
2892static isc_result_t
2893removed(dns_zone_t *zone, void *uap) {
2894	const char *type;
2895
2896	if (dns_zone_getview(zone) != uap)
2897		return (ISC_R_SUCCESS);
2898
2899	switch (dns_zone_gettype(zone)) {
2900	case dns_zone_master:
2901		type = "master";
2902		break;
2903	case dns_zone_slave:
2904		type = "slave";
2905		break;
2906	case dns_zone_stub:
2907		type = "stub";
2908		break;
2909	default:
2910		type = "other";
2911		break;
2912	}
2913	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
2914	return (ISC_R_SUCCESS);
2915}
2916
2917static isc_result_t
2918load_configuration(const char *filename, ns_server_t *server,
2919		   isc_boolean_t first_time)
2920{
2921	cfg_aclconfctx_t aclconfctx;
2922	cfg_obj_t *config;
2923	cfg_parser_t *parser = NULL;
2924	const cfg_listelt_t *element;
2925	const cfg_obj_t *builtin_views;
2926	const cfg_obj_t *maps[3];
2927	const cfg_obj_t *obj;
2928	const cfg_obj_t *options;
2929	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
2930	const cfg_obj_t *views;
2931	dns_view_t *view = NULL;
2932	dns_view_t *view_next;
2933	dns_viewlist_t tmpviewlist;
2934	dns_viewlist_t viewlist;
2935	in_port_t listen_port, udpport_low, udpport_high;
2936	int i;
2937	isc_interval_t interval;
2938	isc_portset_t *v4portset = NULL;
2939	isc_portset_t *v6portset = NULL;
2940	isc_resourcevalue_t nfiles;
2941	isc_result_t result;
2942	isc_uint32_t heartbeat_interval;
2943	isc_uint32_t interface_interval;
2944	isc_uint32_t reserved;
2945	isc_uint32_t udpsize;
2946	unsigned int maxsocks;
2947
2948	cfg_aclconfctx_init(&aclconfctx);
2949	ISC_LIST_INIT(viewlist);
2950
2951	/* Ensure exclusive access to configuration data. */
2952	result = isc_task_beginexclusive(server->task);
2953	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2954
2955	/*
2956	 * Parse the global default pseudo-config file.
2957	 */
2958	if (first_time) {
2959		CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
2960		RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
2961					  &ns_g_defaults) ==
2962			      ISC_R_SUCCESS);
2963	}
2964
2965	/*
2966	 * Parse the configuration file using the new config code.
2967	 */
2968	result = ISC_R_FAILURE;
2969	config = NULL;
2970
2971	/*
2972	 * Unless this is lwresd with the -C option, parse the config file.
2973	 */
2974	if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
2975		isc_log_write(ns_g_lctx,
2976			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2977			      ISC_LOG_INFO, "loading configuration from '%s'",
2978			      filename);
2979		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
2980		cfg_parser_setcallback(parser, directory_callback, NULL);
2981		result = cfg_parse_file(parser, filename, &cfg_type_namedconf,
2982					&config);
2983	}
2984
2985	/*
2986	 * If this is lwresd with the -C option, or lwresd with no -C or -c
2987	 * option where the above parsing failed, parse resolv.conf.
2988	 */
2989	if (ns_g_lwresdonly &&
2990	    (lwresd_g_useresolvconf ||
2991	     (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
2992	{
2993		isc_log_write(ns_g_lctx,
2994			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2995			      ISC_LOG_INFO, "loading configuration from '%s'",
2996			      lwresd_g_resolvconffile);
2997		if (parser != NULL)
2998			cfg_parser_destroy(&parser);
2999		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
3000		result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser,
3001						    &config);
3002	}
3003	CHECK(result);
3004
3005	/*
3006	 * Check the validity of the configuration.
3007	 */
3008	CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
3009
3010	/*
3011	 * Fill in the maps array, used for resolving defaults.
3012	 */
3013	i = 0;
3014	options = NULL;
3015	result = cfg_map_get(config, "options", &options);
3016	if (result == ISC_R_SUCCESS)
3017		maps[i++] = options;
3018	maps[i++] = ns_g_defaults;
3019	maps[i++] = NULL;
3020
3021	/*
3022	 * Set process limits, which (usually) needs to be done as root.
3023	 */
3024	set_limits(maps);
3025
3026	/*
3027	 * Check if max number of open sockets that the system allows is
3028	 * sufficiently large.  Failing this condition is not necessarily fatal,
3029	 * but may cause subsequent runtime failures for a busy recursive
3030	 * server.
3031	 */
3032	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
3033	if (result != ISC_R_SUCCESS)
3034		maxsocks = 0;
3035	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
3036	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
3037		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3038			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3039			      "max open files (%" ISC_PRINT_QUADFORMAT "u)"
3040			      " is smaller than max sockets (%u)",
3041			      nfiles, maxsocks);
3042	}
3043
3044	/*
3045	 * Set the number of socket reserved for TCP, stdio etc.
3046	 */
3047	obj = NULL;
3048	result = ns_config_get(maps, "reserved-sockets", &obj);
3049	INSIST(result == ISC_R_SUCCESS);
3050	reserved = cfg_obj_asuint32(obj);
3051	if (maxsocks != 0) {
3052		if (maxsocks < 128U)			/* Prevent underflow. */
3053			reserved = 0;
3054		else if (reserved > maxsocks - 128U)	/* Minimum UDP space. */
3055			reserved = maxsocks - 128;
3056	}
3057	/* Minimum TCP/stdio space. */
3058	if (reserved < 128U)
3059		reserved = 128;
3060	if (reserved + 128U > maxsocks && maxsocks != 0) {
3061		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3062			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3063			      "less than 128 UDP sockets available after "
3064			      "applying 'reserved-sockets' and 'maxsockets'");
3065	}
3066	isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
3067
3068	/*
3069	 * Configure various server options.
3070	 */
3071	configure_server_quota(maps, "transfers-out", &server->xfroutquota);
3072	configure_server_quota(maps, "tcp-clients", &server->tcpquota);
3073	configure_server_quota(maps, "recursive-clients",
3074			       &server->recursionquota);
3075	if (server->recursionquota.max > 1000)
3076		isc_quota_soft(&server->recursionquota,
3077			       server->recursionquota.max - 100);
3078	else
3079		isc_quota_soft(&server->recursionquota, 0);
3080
3081	CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
3082				 ns_g_mctx, &server->blackholeacl));
3083	if (server->blackholeacl != NULL)
3084		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
3085					     server->blackholeacl);
3086
3087	obj = NULL;
3088	result = ns_config_get(maps, "match-mapped-addresses", &obj);
3089	INSIST(result == ISC_R_SUCCESS);
3090	server->aclenv.match_mapped = cfg_obj_asboolean(obj);
3091
3092	CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx),
3093	       "configuring statistics server(s)");
3094
3095	/*
3096	 * Configure sets of UDP query source ports.
3097	 */
3098	CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
3099	       "creating UDP port set");
3100	CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
3101	       "creating UDP port set");
3102
3103	usev4ports = NULL;
3104	usev6ports = NULL;
3105	avoidv4ports = NULL;
3106	avoidv6ports = NULL;
3107
3108	(void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
3109	if (usev4ports != NULL)
3110		portset_fromconf(v4portset, usev4ports, ISC_TRUE);
3111	else {
3112		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
3113					       &udpport_high),
3114		       "get the default UDP/IPv4 port range");
3115		if (udpport_low == udpport_high)
3116			isc_portset_add(v4portset, udpport_low);
3117		else {
3118			isc_portset_addrange(v4portset, udpport_low,
3119					     udpport_high);
3120		}
3121		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3122			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3123			      "using default UDP/IPv4 port range: [%d, %d]",
3124			      udpport_low, udpport_high);
3125	}
3126	(void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
3127	if (avoidv4ports != NULL)
3128		portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
3129
3130	(void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
3131	if (usev6ports != NULL)
3132		portset_fromconf(v6portset, usev6ports, ISC_TRUE);
3133	else {
3134		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
3135					       &udpport_high),
3136		       "get the default UDP/IPv6 port range");
3137		if (udpport_low == udpport_high)
3138			isc_portset_add(v6portset, udpport_low);
3139		else {
3140			isc_portset_addrange(v6portset, udpport_low,
3141					     udpport_high);
3142		}
3143		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3144			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3145			      "using default UDP/IPv6 port range: [%d, %d]",
3146			      udpport_low, udpport_high);
3147	}
3148	(void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
3149	if (avoidv6ports != NULL)
3150		portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
3151
3152	dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
3153
3154	/*
3155	 * Set the EDNS UDP size when we don't match a view.
3156	 */
3157	obj = NULL;
3158	result = ns_config_get(maps, "edns-udp-size", &obj);
3159	INSIST(result == ISC_R_SUCCESS);
3160	udpsize = cfg_obj_asuint32(obj);
3161	if (udpsize < 512)
3162		udpsize = 512;
3163	if (udpsize > 4096)
3164		udpsize = 4096;
3165	ns_g_udpsize = (isc_uint16_t)udpsize;
3166
3167	/*
3168	 * Configure the zone manager.
3169	 */
3170	obj = NULL;
3171	result = ns_config_get(maps, "transfers-in", &obj);
3172	INSIST(result == ISC_R_SUCCESS);
3173	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
3174
3175	obj = NULL;
3176	result = ns_config_get(maps, "transfers-per-ns", &obj);
3177	INSIST(result == ISC_R_SUCCESS);
3178	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
3179
3180	obj = NULL;
3181	result = ns_config_get(maps, "serial-query-rate", &obj);
3182	INSIST(result == ISC_R_SUCCESS);
3183	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
3184
3185	/*
3186	 * Determine which port to use for listening for incoming connections.
3187	 */
3188	if (ns_g_port != 0)
3189		listen_port = ns_g_port;
3190	else
3191		CHECKM(ns_config_getport(config, &listen_port), "port");
3192
3193	/*
3194	 * Find the listen queue depth.
3195	 */
3196	obj = NULL;
3197	result = ns_config_get(maps, "tcp-listen-queue", &obj);
3198	INSIST(result == ISC_R_SUCCESS);
3199	ns_g_listen = cfg_obj_asuint32(obj);
3200	if (ns_g_listen < 3)
3201		ns_g_listen = 3;
3202
3203	/*
3204	 * Configure the interface manager according to the "listen-on"
3205	 * statement.
3206	 */
3207	{
3208		const cfg_obj_t *clistenon = NULL;
3209		ns_listenlist_t *listenon = NULL;
3210
3211		clistenon = NULL;
3212		/*
3213		 * Even though listen-on is present in the default
3214		 * configuration, we can't use it here, since it isn't
3215		 * used if we're in lwresd mode.  This way is easier.
3216		 */
3217		if (options != NULL)
3218			(void)cfg_map_get(options, "listen-on", &clistenon);
3219		if (clistenon != NULL) {
3220			result = ns_listenlist_fromconfig(clistenon,
3221							  config,
3222							  &aclconfctx,
3223							  ns_g_mctx,
3224							  &listenon);
3225		} else if (!ns_g_lwresdonly) {
3226			/*
3227			 * Not specified, use default.
3228			 */
3229			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
3230						    ISC_TRUE, &listenon));
3231		}
3232		if (listenon != NULL) {
3233			ns_interfacemgr_setlistenon4(server->interfacemgr,
3234						     listenon);
3235			ns_listenlist_detach(&listenon);
3236		}
3237	}
3238	/*
3239	 * Ditto for IPv6.
3240	 */
3241	{
3242		const cfg_obj_t *clistenon = NULL;
3243		ns_listenlist_t *listenon = NULL;
3244
3245		if (options != NULL)
3246			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
3247		if (clistenon != NULL) {
3248			result = ns_listenlist_fromconfig(clistenon,
3249							  config,
3250							  &aclconfctx,
3251							  ns_g_mctx,
3252							  &listenon);
3253		} else if (!ns_g_lwresdonly) {
3254			isc_boolean_t enable;
3255			/*
3256			 * Not specified, use default.
3257			 */
3258			enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS);
3259			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
3260						    enable, &listenon));
3261		}
3262		if (listenon != NULL) {
3263			ns_interfacemgr_setlistenon6(server->interfacemgr,
3264						     listenon);
3265			ns_listenlist_detach(&listenon);
3266		}
3267	}
3268
3269	/*
3270	 * Rescan the interface list to pick up changes in the
3271	 * listen-on option.  It's important that we do this before we try
3272	 * to configure the query source, since the dispatcher we use might
3273	 * be shared with an interface.
3274	 */
3275	scan_interfaces(server, ISC_TRUE);
3276
3277	/*
3278	 * Arrange for further interface scanning to occur periodically
3279	 * as specified by the "interface-interval" option.
3280	 */
3281	obj = NULL;
3282	result = ns_config_get(maps, "interface-interval", &obj);
3283	INSIST(result == ISC_R_SUCCESS);
3284	interface_interval = cfg_obj_asuint32(obj) * 60;
3285	if (interface_interval == 0) {
3286		CHECK(isc_timer_reset(server->interface_timer,
3287				      isc_timertype_inactive,
3288				      NULL, NULL, ISC_TRUE));
3289	} else if (server->interface_interval != interface_interval) {
3290		isc_interval_set(&interval, interface_interval, 0);
3291		CHECK(isc_timer_reset(server->interface_timer,
3292				      isc_timertype_ticker,
3293				      NULL, &interval, ISC_FALSE));
3294	}
3295	server->interface_interval = interface_interval;
3296
3297	/*
3298	 * Configure the dialup heartbeat timer.
3299	 */
3300	obj = NULL;
3301	result = ns_config_get(maps, "heartbeat-interval", &obj);
3302	INSIST(result == ISC_R_SUCCESS);
3303	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
3304	if (heartbeat_interval == 0) {
3305		CHECK(isc_timer_reset(server->heartbeat_timer,
3306				      isc_timertype_inactive,
3307				      NULL, NULL, ISC_TRUE));
3308	} else if (server->heartbeat_interval != heartbeat_interval) {
3309		isc_interval_set(&interval, heartbeat_interval, 0);
3310		CHECK(isc_timer_reset(server->heartbeat_timer,
3311				      isc_timertype_ticker,
3312				      NULL, &interval, ISC_FALSE));
3313	}
3314	server->heartbeat_interval = heartbeat_interval;
3315
3316	isc_interval_set(&interval, 1200, 0);
3317	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
3318			      &interval, ISC_FALSE));
3319
3320	/*
3321	 * Configure and freeze all explicit views.  Explicit
3322	 * views that have zones were already created at parsing
3323	 * time, but views with no zones must be created here.
3324	 */
3325	views = NULL;
3326	(void)cfg_map_get(config, "view", &views);
3327	for (element = cfg_list_first(views);
3328	     element != NULL;
3329	     element = cfg_list_next(element))
3330	{
3331		const cfg_obj_t *vconfig = cfg_listelt_value(element);
3332		view = NULL;
3333
3334		CHECK(create_view(vconfig, &viewlist, &view));
3335		INSIST(view != NULL);
3336		CHECK(configure_view(view, config, vconfig,
3337				     ns_g_mctx, &aclconfctx, ISC_TRUE));
3338		dns_view_freeze(view);
3339		dns_view_detach(&view);
3340	}
3341
3342	/*
3343	 * Make sure we have a default view if and only if there
3344	 * were no explicit views.
3345	 */
3346	if (views == NULL) {
3347		/*
3348		 * No explicit views; there ought to be a default view.
3349		 * There may already be one created as a side effect
3350		 * of zone statements, or we may have to create one.
3351		 * In either case, we need to configure and freeze it.
3352		 */
3353		CHECK(create_view(NULL, &viewlist, &view));
3354		CHECK(configure_view(view, config, NULL, ns_g_mctx,
3355				     &aclconfctx, ISC_TRUE));
3356		dns_view_freeze(view);
3357		dns_view_detach(&view);
3358	}
3359
3360	/*
3361	 * Create (or recreate) the built-in views.  Currently
3362	 * there is only one, the _bind view.
3363	 */
3364	builtin_views = NULL;
3365	RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
3366				  &builtin_views) == ISC_R_SUCCESS);
3367	for (element = cfg_list_first(builtin_views);
3368	     element != NULL;
3369	     element = cfg_list_next(element))
3370	{
3371		const cfg_obj_t *vconfig = cfg_listelt_value(element);
3372		CHECK(create_view(vconfig, &viewlist, &view));
3373		CHECK(configure_view(view, config, vconfig, ns_g_mctx,
3374				     &aclconfctx, ISC_FALSE));
3375		dns_view_freeze(view);
3376		dns_view_detach(&view);
3377		view = NULL;
3378	}
3379
3380	/*
3381	 * Swap our new view list with the production one.
3382	 */
3383	tmpviewlist = server->viewlist;
3384	server->viewlist = viewlist;
3385	viewlist = tmpviewlist;
3386
3387	/*
3388	 * Load the TKEY information from the configuration.
3389	 */
3390	if (options != NULL) {
3391		dns_tkeyctx_t *t = NULL;
3392		CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
3393					     &t),
3394		       "configuring TKEY");
3395		if (server->tkeyctx != NULL)
3396			dns_tkeyctx_destroy(&server->tkeyctx);
3397		server->tkeyctx = t;
3398	}
3399
3400	/*
3401	 * Bind the control port(s).
3402	 */
3403	CHECKM(ns_controls_configure(ns_g_server->controls, config,
3404				     &aclconfctx),
3405	       "binding control channel(s)");
3406
3407	/*
3408	 * Bind the lwresd port(s).
3409	 */
3410	CHECKM(ns_lwresd_configure(ns_g_mctx, config),
3411	       "binding lightweight resolver ports");
3412
3413	/*
3414	 * Open the source of entropy.
3415	 */
3416	if (first_time) {
3417		obj = NULL;
3418		result = ns_config_get(maps, "random-device", &obj);
3419		if (result != ISC_R_SUCCESS) {
3420			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3421				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3422				      "no source of entropy found");
3423		} else {
3424			const char *randomdev = cfg_obj_asstring(obj);
3425			result = isc_entropy_createfilesource(ns_g_entropy,
3426							      randomdev);
3427			if (result != ISC_R_SUCCESS)
3428				isc_log_write(ns_g_lctx,
3429					      NS_LOGCATEGORY_GENERAL,
3430					      NS_LOGMODULE_SERVER,
3431					      ISC_LOG_INFO,
3432					      "could not open entropy source "
3433					      "%s: %s",
3434					      randomdev,
3435					      isc_result_totext(result));
3436#ifdef PATH_RANDOMDEV
3437			if (ns_g_fallbackentropy != NULL) {
3438				if (result != ISC_R_SUCCESS) {
3439					isc_log_write(ns_g_lctx,
3440						      NS_LOGCATEGORY_GENERAL,
3441						      NS_LOGMODULE_SERVER,
3442						      ISC_LOG_INFO,
3443						      "using pre-chroot entropy source "
3444						      "%s",
3445						      PATH_RANDOMDEV);
3446					isc_entropy_detach(&ns_g_entropy);
3447					isc_entropy_attach(ns_g_fallbackentropy,
3448							   &ns_g_entropy);
3449				}
3450				isc_entropy_detach(&ns_g_fallbackentropy);
3451			}
3452#endif
3453		}
3454	}
3455
3456	/*
3457	 * Relinquish root privileges.
3458	 */
3459	if (first_time)
3460		ns_os_changeuser();
3461
3462	/*
3463	 * Check that the working directory is writable.
3464	 */
3465	if (access(".", W_OK) != 0) {
3466		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3467			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3468			      "the working directory is not writable");
3469	}
3470
3471	/*
3472	 * Configure the logging system.
3473	 *
3474	 * Do this after changing UID to make sure that any log
3475	 * files specified in named.conf get created by the
3476	 * unprivileged user, not root.
3477	 */
3478	if (ns_g_logstderr) {
3479		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3480			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3481			      "ignoring config file logging "
3482			      "statement due to -g option");
3483	} else {
3484		const cfg_obj_t *logobj = NULL;
3485		isc_logconfig_t *logc = NULL;
3486
3487		CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
3488		       "creating new logging configuration");
3489
3490		logobj = NULL;
3491		(void)cfg_map_get(config, "logging", &logobj);
3492		if (logobj != NULL) {
3493			CHECKM(ns_log_configure(logc, logobj),
3494			       "configuring logging");
3495		} else {
3496			CHECKM(ns_log_setdefaultchannels(logc),
3497			       "setting up default logging channels");
3498			CHECKM(ns_log_setunmatchedcategory(logc),
3499			       "setting up default 'category unmatched'");
3500			CHECKM(ns_log_setdefaultcategory(logc),
3501			       "setting up default 'category default'");
3502		}
3503
3504		result = isc_logconfig_use(ns_g_lctx, logc);
3505		if (result != ISC_R_SUCCESS) {
3506			isc_logconfig_destroy(&logc);
3507			CHECKM(result, "installing logging configuration");
3508		}
3509
3510		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3511			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
3512			      "now using logging configuration from "
3513			      "config file");
3514	}
3515
3516	/*
3517	 * Set the default value of the query logging flag depending
3518	 * whether a "queries" category has been defined.  This is
3519	 * a disgusting hack, but we need to do this for BIND 8
3520	 * compatibility.
3521	 */
3522	if (first_time) {
3523		const cfg_obj_t *logobj = NULL;
3524		const cfg_obj_t *categories = NULL;
3525
3526		obj = NULL;
3527		if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
3528			server->log_queries = cfg_obj_asboolean(obj);
3529		} else {
3530
3531			(void)cfg_map_get(config, "logging", &logobj);
3532			if (logobj != NULL)
3533				(void)cfg_map_get(logobj, "category",
3534						  &categories);
3535			if (categories != NULL) {
3536				const cfg_listelt_t *element;
3537				for (element = cfg_list_first(categories);
3538				     element != NULL;
3539				     element = cfg_list_next(element))
3540				{
3541					const cfg_obj_t *catobj;
3542					const char *str;
3543
3544					obj = cfg_listelt_value(element);
3545					catobj = cfg_tuple_get(obj, "name");
3546					str = cfg_obj_asstring(catobj);
3547					if (strcasecmp(str, "queries") == 0)
3548						server->log_queries = ISC_TRUE;
3549				}
3550			}
3551		}
3552	}
3553
3554	obj = NULL;
3555	if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
3556		if (cfg_obj_isvoid(obj))
3557			ns_os_writepidfile(NULL, first_time);
3558		else
3559			ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
3560	else if (ns_g_lwresdonly)
3561		ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
3562	else
3563		ns_os_writepidfile(ns_g_defaultpidfile, first_time);
3564
3565	obj = NULL;
3566	if (options != NULL &&
3567	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
3568		ns_g_memstatistics = cfg_obj_asboolean(obj);
3569	else
3570		ns_g_memstatistics =
3571			ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
3572
3573	obj = NULL;
3574	if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
3575		ns_main_setmemstats(cfg_obj_asstring(obj));
3576	else if (ns_g_memstatistics)
3577		ns_main_setmemstats("named.memstats");
3578	else
3579		ns_main_setmemstats(NULL);
3580
3581	obj = NULL;
3582	result = ns_config_get(maps, "statistics-file", &obj);
3583	INSIST(result == ISC_R_SUCCESS);
3584	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
3585	       "strdup");
3586
3587	obj = NULL;
3588	result = ns_config_get(maps, "dump-file", &obj);
3589	INSIST(result == ISC_R_SUCCESS);
3590	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
3591	       "strdup");
3592
3593	obj = NULL;
3594	result = ns_config_get(maps, "recursing-file", &obj);
3595	INSIST(result == ISC_R_SUCCESS);
3596	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
3597	       "strdup");
3598
3599	obj = NULL;
3600	result = ns_config_get(maps, "version", &obj);
3601	if (result == ISC_R_SUCCESS) {
3602		CHECKM(setoptstring(server, &server->version, obj), "strdup");
3603		server->version_set = ISC_TRUE;
3604	} else {
3605		server->version_set = ISC_FALSE;
3606	}
3607
3608	obj = NULL;
3609	result = ns_config_get(maps, "hostname", &obj);
3610	if (result == ISC_R_SUCCESS) {
3611		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
3612		server->hostname_set = ISC_TRUE;
3613	} else {
3614		server->hostname_set = ISC_FALSE;
3615	}
3616
3617	obj = NULL;
3618	result = ns_config_get(maps, "server-id", &obj);
3619	server->server_usehostname = ISC_FALSE;
3620	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3621		/* The parser translates "hostname" to ISC_TRUE */
3622		server->server_usehostname = cfg_obj_asboolean(obj);
3623		result = setstring(server, &server->server_id, NULL);
3624		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3625	} else if (result == ISC_R_SUCCESS) {
3626		/* Found a quoted string */
3627		CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
3628	} else {
3629		result = setstring(server, &server->server_id, NULL);
3630		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3631	}
3632
3633	obj = NULL;
3634	result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
3635	if (result == ISC_R_SUCCESS) {
3636		server->flushonshutdown = cfg_obj_asboolean(obj);
3637	} else {
3638		server->flushonshutdown = ISC_FALSE;
3639	}
3640
3641	result = ISC_R_SUCCESS;
3642
3643 cleanup:
3644	if (v4portset != NULL)
3645		isc_portset_destroy(ns_g_mctx, &v4portset);
3646
3647	if (v6portset != NULL)
3648		isc_portset_destroy(ns_g_mctx, &v6portset);
3649
3650	cfg_aclconfctx_destroy(&aclconfctx);
3651
3652	if (parser != NULL) {
3653		if (config != NULL)
3654			cfg_obj_destroy(parser, &config);
3655		cfg_parser_destroy(&parser);
3656	}
3657
3658	if (view != NULL)
3659		dns_view_detach(&view);
3660
3661	/*
3662	 * This cleans up either the old production view list
3663	 * or our temporary list depending on whether they
3664	 * were swapped above or not.
3665	 */
3666	for (view = ISC_LIST_HEAD(viewlist);
3667	     view != NULL;
3668	     view = view_next) {
3669		view_next = ISC_LIST_NEXT(view, link);
3670		ISC_LIST_UNLINK(viewlist, view, link);
3671		if (result == ISC_R_SUCCESS &&
3672		    strcmp(view->name, "_bind") != 0)
3673			(void)dns_zt_apply(view->zonetable, ISC_FALSE,
3674					   removed, view);
3675		dns_view_detach(&view);
3676	}
3677
3678	/*
3679	 * Adjust the listening interfaces in accordance with the source
3680	 * addresses specified in views and zones.
3681	 */
3682	if (isc_net_probeipv6() == ISC_R_SUCCESS)
3683		adjust_interfaces(server, ns_g_mctx);
3684
3685	/* Relinquish exclusive access to configuration data. */
3686	isc_task_endexclusive(server->task);
3687
3688	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3689		      ISC_LOG_DEBUG(1), "load_configuration: %s",
3690		      isc_result_totext(result));
3691
3692	return (result);
3693}
3694
3695static isc_result_t
3696load_zones(ns_server_t *server, isc_boolean_t stop) {
3697	isc_result_t result;
3698	dns_view_t *view;
3699
3700	result = isc_task_beginexclusive(server->task);
3701	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3702
3703	/*
3704	 * Load zone data from disk.
3705	 */
3706	for (view = ISC_LIST_HEAD(server->viewlist);
3707	     view != NULL;
3708	     view = ISC_LIST_NEXT(view, link))
3709	{
3710		CHECK(dns_view_load(view, stop));
3711	}
3712
3713	/*
3714	 * Force zone maintenance.  Do this after loading
3715	 * so that we know when we need to force AXFR of
3716	 * slave zones whose master files are missing.
3717	 */
3718	CHECK(dns_zonemgr_forcemaint(server->zonemgr));
3719 cleanup:
3720	isc_task_endexclusive(server->task);
3721	return (result);
3722}
3723
3724static isc_result_t
3725load_new_zones(ns_server_t *server, isc_boolean_t stop) {
3726	isc_result_t result;
3727	dns_view_t *view;
3728
3729	result = isc_task_beginexclusive(server->task);
3730	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3731
3732	/*
3733	 * Load zone data from disk.
3734	 */
3735	for (view = ISC_LIST_HEAD(server->viewlist);
3736	     view != NULL;
3737	     view = ISC_LIST_NEXT(view, link))
3738	{
3739		CHECK(dns_view_loadnew(view, stop));
3740	}
3741	/*
3742	 * Force zone maintenance.  Do this after loading
3743	 * so that we know when we need to force AXFR of
3744	 * slave zones whose master files are missing.
3745	 */
3746	dns_zonemgr_resumexfrs(server->zonemgr);
3747 cleanup:
3748	isc_task_endexclusive(server->task);
3749	return (result);
3750}
3751
3752static void
3753run_server(isc_task_t *task, isc_event_t *event) {
3754	isc_result_t result;
3755	ns_server_t *server = (ns_server_t *)event->ev_arg;
3756
3757	INSIST(task == server->task);
3758
3759	isc_event_free(&event);
3760
3761	CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
3762					  &ns_g_dispatchmgr),
3763		   "creating dispatch manager");
3764
3765	dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
3766
3767	CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
3768					  ns_g_socketmgr, ns_g_dispatchmgr,
3769					  &server->interfacemgr),
3770		   "creating interface manager");
3771
3772	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3773				    NULL, NULL, server->task,
3774				    interface_timer_tick,
3775				    server, &server->interface_timer),
3776		   "creating interface timer");
3777
3778	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3779				    NULL, NULL, server->task,
3780				    heartbeat_timer_tick,
3781				    server, &server->heartbeat_timer),
3782		   "creating heartbeat timer");
3783
3784	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3785				    NULL, NULL, server->task, pps_timer_tick,
3786				    server, &server->pps_timer),
3787		   "creating pps timer");
3788
3789	CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
3790		   "creating default configuration parser");
3791
3792	if (ns_g_lwresdonly)
3793		CHECKFATAL(load_configuration(lwresd_g_conffile, server,
3794					      ISC_TRUE),
3795			   "loading configuration");
3796	else
3797		CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
3798			   "loading configuration");
3799
3800	isc_hash_init();
3801
3802	CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones");
3803
3804	ns_os_started();
3805	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3806		      ISC_LOG_NOTICE, "running");
3807}
3808
3809void
3810ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
3811
3812	REQUIRE(NS_SERVER_VALID(server));
3813
3814	server->flushonshutdown = flush;
3815}
3816
3817static void
3818shutdown_server(isc_task_t *task, isc_event_t *event) {
3819	isc_result_t result;
3820	dns_view_t *view, *view_next;
3821	ns_server_t *server = (ns_server_t *)event->ev_arg;
3822	isc_boolean_t flush = server->flushonshutdown;
3823
3824	UNUSED(task);
3825	INSIST(task == server->task);
3826
3827	result = isc_task_beginexclusive(server->task);
3828	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3829
3830	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3831		      ISC_LOG_INFO, "shutting down%s",
3832		      flush ? ": flushing changes" : "");
3833
3834	ns_statschannels_shutdown(server);
3835	ns_controls_shutdown(server->controls);
3836	end_reserved_dispatches(server, ISC_TRUE);
3837
3838	cfg_obj_destroy(ns_g_parser, &ns_g_config);
3839	cfg_parser_destroy(&ns_g_parser);
3840
3841	for (view = ISC_LIST_HEAD(server->viewlist);
3842	     view != NULL;
3843	     view = view_next) {
3844		view_next = ISC_LIST_NEXT(view, link);
3845		ISC_LIST_UNLINK(server->viewlist, view, link);
3846		if (flush)
3847			dns_view_flushanddetach(&view);
3848		else
3849			dns_view_detach(&view);
3850	}
3851
3852	isc_timer_detach(&server->interface_timer);
3853	isc_timer_detach(&server->heartbeat_timer);
3854	isc_timer_detach(&server->pps_timer);
3855
3856	ns_interfacemgr_shutdown(server->interfacemgr);
3857	ns_interfacemgr_detach(&server->interfacemgr);
3858
3859	dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
3860
3861	dns_zonemgr_shutdown(server->zonemgr);
3862
3863	if (server->blackholeacl != NULL)
3864		dns_acl_detach(&server->blackholeacl);
3865
3866	dns_db_detach(&server->in_roothints);
3867
3868	isc_task_endexclusive(server->task);
3869
3870	isc_task_detach(&server->task);
3871
3872	isc_event_free(&event);
3873}
3874
3875void
3876ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
3877	isc_result_t result;
3878
3879	ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
3880	if (server == NULL)
3881		fatal("allocating server object", ISC_R_NOMEMORY);
3882
3883	server->mctx = mctx;
3884	server->task = NULL;
3885
3886	/* Initialize configuration data with default values. */
3887
3888	result = isc_quota_init(&server->xfroutquota, 10);
3889	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3890	result = isc_quota_init(&server->tcpquota, 10);
3891	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3892	result = isc_quota_init(&server->recursionquota, 100);
3893	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3894
3895	result = dns_aclenv_init(mctx, &server->aclenv);
3896	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3897
3898	/* Initialize server data structures. */
3899	server->zonemgr = NULL;
3900	server->interfacemgr = NULL;
3901	ISC_LIST_INIT(server->viewlist);
3902	server->in_roothints = NULL;
3903	server->blackholeacl = NULL;
3904
3905	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
3906				     &server->in_roothints),
3907		   "setting up root hints");
3908
3909	CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
3910		   "initializing reload event lock");
3911	server->reload_event =
3912		isc_event_allocate(ns_g_mctx, server,
3913				   NS_EVENT_RELOAD,
3914				   ns_server_reload,
3915				   server,
3916				   sizeof(isc_event_t));
3917	CHECKFATAL(server->reload_event == NULL ?
3918		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
3919		   "allocating reload event");
3920
3921	CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
3922		   "initializing DST");
3923
3924	server->tkeyctx = NULL;
3925	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
3926				      &server->tkeyctx),
3927		   "creating TKEY context");
3928
3929	/*
3930	 * Setup the server task, which is responsible for coordinating
3931	 * startup and shutdown of the server.
3932	 */
3933	CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
3934		   "creating server task");
3935	isc_task_setname(server->task, "server", server);
3936	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
3937		   "isc_task_onshutdown");
3938	CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
3939		   "isc_app_onrun");
3940
3941	server->interface_timer = NULL;
3942	server->heartbeat_timer = NULL;
3943	server->pps_timer = NULL;
3944
3945	server->interface_interval = 0;
3946	server->heartbeat_interval = 0;
3947
3948	CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
3949				      ns_g_socketmgr, &server->zonemgr),
3950		   "dns_zonemgr_create");
3951
3952	server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
3953	CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3954		   "isc_mem_strdup");
3955	server->nsstats = NULL;
3956	server->rcvquerystats = NULL;
3957	server->opcodestats = NULL;
3958	server->zonestats = NULL;
3959	server->resolverstats = NULL;
3960	server->sockstats = NULL;
3961	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
3962				    isc_sockstatscounter_max),
3963		   "isc_stats_create");
3964	isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
3965
3966	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
3967	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3968		   "isc_mem_strdup");
3969
3970	server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
3971	CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3972		   "isc_mem_strdup");
3973
3974	server->hostname_set = ISC_FALSE;
3975	server->hostname = NULL;
3976	server->version_set = ISC_FALSE;
3977	server->version = NULL;
3978	server->server_usehostname = ISC_FALSE;
3979	server->server_id = NULL;
3980
3981	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
3982				    dns_nsstatscounter_max),
3983		   "dns_stats_create (server)");
3984
3985	CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
3986					     &server->rcvquerystats),
3987		   "dns_stats_create (rcvquery)");
3988
3989	CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
3990		   "dns_stats_create (opcode)");
3991
3992	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
3993				    dns_zonestatscounter_max),
3994		   "dns_stats_create (zone)");
3995
3996	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
3997				    dns_resstatscounter_max),
3998		   "dns_stats_create (resolver)");
3999
4000	server->flushonshutdown = ISC_FALSE;
4001	server->log_queries = ISC_FALSE;
4002
4003	server->controls = NULL;
4004	CHECKFATAL(ns_controls_create(server, &server->controls),
4005		   "ns_controls_create");
4006	server->dispatchgen = 0;
4007	ISC_LIST_INIT(server->dispatches);
4008
4009	ISC_LIST_INIT(server->statschannels);
4010
4011	server->magic = NS_SERVER_MAGIC;
4012	*serverp = server;
4013}
4014
4015void
4016ns_server_destroy(ns_server_t **serverp) {
4017	ns_server_t *server = *serverp;
4018	REQUIRE(NS_SERVER_VALID(server));
4019
4020	ns_controls_destroy(&server->controls);
4021
4022	isc_stats_detach(&server->nsstats);
4023	dns_stats_detach(&server->rcvquerystats);
4024	dns_stats_detach(&server->opcodestats);
4025	isc_stats_detach(&server->zonestats);
4026	isc_stats_detach(&server->resolverstats);
4027	isc_stats_detach(&server->sockstats);
4028
4029	isc_mem_free(server->mctx, server->statsfile);
4030	isc_mem_free(server->mctx, server->dumpfile);
4031	isc_mem_free(server->mctx, server->recfile);
4032
4033	if (server->version != NULL)
4034		isc_mem_free(server->mctx, server->version);
4035	if (server->hostname != NULL)
4036		isc_mem_free(server->mctx, server->hostname);
4037	if (server->server_id != NULL)
4038		isc_mem_free(server->mctx, server->server_id);
4039
4040	dns_zonemgr_detach(&server->zonemgr);
4041
4042	if (server->tkeyctx != NULL)
4043		dns_tkeyctx_destroy(&server->tkeyctx);
4044
4045	dst_lib_destroy();
4046
4047	isc_event_free(&server->reload_event);
4048
4049	INSIST(ISC_LIST_EMPTY(server->viewlist));
4050
4051	dns_aclenv_destroy(&server->aclenv);
4052
4053	isc_quota_destroy(&server->recursionquota);
4054	isc_quota_destroy(&server->tcpquota);
4055	isc_quota_destroy(&server->xfroutquota);
4056
4057	server->magic = 0;
4058	isc_mem_put(server->mctx, server, sizeof(*server));
4059	*serverp = NULL;
4060}
4061
4062static void
4063fatal(const char *msg, isc_result_t result) {
4064	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4065		      ISC_LOG_CRITICAL, "%s: %s", msg,
4066		      isc_result_totext(result));
4067	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4068		      ISC_LOG_CRITICAL, "exiting (due to fatal error)");
4069	exit(1);
4070}
4071
4072static void
4073start_reserved_dispatches(ns_server_t *server) {
4074
4075	REQUIRE(NS_SERVER_VALID(server));
4076
4077	server->dispatchgen++;
4078}
4079
4080static void
4081end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
4082	ns_dispatch_t *dispatch, *nextdispatch;
4083
4084	REQUIRE(NS_SERVER_VALID(server));
4085
4086	for (dispatch = ISC_LIST_HEAD(server->dispatches);
4087	     dispatch != NULL;
4088	     dispatch = nextdispatch) {
4089		nextdispatch = ISC_LIST_NEXT(dispatch, link);
4090		if (!all && server->dispatchgen == dispatch-> dispatchgen)
4091			continue;
4092		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
4093		dns_dispatch_detach(&dispatch->dispatch);
4094		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
4095	}
4096}
4097
4098void
4099ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
4100	ns_dispatch_t *dispatch;
4101	in_port_t port;
4102	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
4103	isc_result_t result;
4104	unsigned int attrs, attrmask;
4105
4106	REQUIRE(NS_SERVER_VALID(server));
4107
4108	port = isc_sockaddr_getport(addr);
4109	if (port == 0 || port >= 1024)
4110		return;
4111
4112	for (dispatch = ISC_LIST_HEAD(server->dispatches);
4113	     dispatch != NULL;
4114	     dispatch = ISC_LIST_NEXT(dispatch, link)) {
4115		if (isc_sockaddr_equal(&dispatch->addr, addr))
4116			break;
4117	}
4118	if (dispatch != NULL) {
4119		dispatch->dispatchgen = server->dispatchgen;
4120		return;
4121	}
4122
4123	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
4124	if (dispatch == NULL) {
4125		result = ISC_R_NOMEMORY;
4126		goto cleanup;
4127	}
4128
4129	dispatch->addr = *addr;
4130	dispatch->dispatchgen = server->dispatchgen;
4131	dispatch->dispatch = NULL;
4132
4133	attrs = 0;
4134	attrs |= DNS_DISPATCHATTR_UDP;
4135	switch (isc_sockaddr_pf(addr)) {
4136	case AF_INET:
4137		attrs |= DNS_DISPATCHATTR_IPV4;
4138		break;
4139	case AF_INET6:
4140		attrs |= DNS_DISPATCHATTR_IPV6;
4141		break;
4142	default:
4143		result = ISC_R_NOTIMPLEMENTED;
4144		goto cleanup;
4145	}
4146	attrmask = 0;
4147	attrmask |= DNS_DISPATCHATTR_UDP;
4148	attrmask |= DNS_DISPATCHATTR_TCP;
4149	attrmask |= DNS_DISPATCHATTR_IPV4;
4150	attrmask |= DNS_DISPATCHATTR_IPV6;
4151
4152	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
4153				     ns_g_taskmgr, &dispatch->addr, 4096,
4154				     1000, 32768, 16411, 16433,
4155				     attrs, attrmask, &dispatch->dispatch);
4156	if (result != ISC_R_SUCCESS)
4157		goto cleanup;
4158
4159	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
4160
4161	return;
4162
4163 cleanup:
4164	if (dispatch != NULL)
4165		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
4166	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
4167	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4168		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4169		      "unable to create dispatch for reserved port %s: %s",
4170		      addrbuf, isc_result_totext(result));
4171}
4172
4173
4174static isc_result_t
4175loadconfig(ns_server_t *server) {
4176	isc_result_t result;
4177	start_reserved_dispatches(server);
4178	result = load_configuration(ns_g_lwresdonly ?
4179				    lwresd_g_conffile : ns_g_conffile,
4180				    server, ISC_FALSE);
4181	if (result == ISC_R_SUCCESS) {
4182		end_reserved_dispatches(server, ISC_FALSE);
4183		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4184			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4185			      "reloading configuration succeeded");
4186	} else {
4187		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4188			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4189			      "reloading configuration failed: %s",
4190			      isc_result_totext(result));
4191	}
4192	return (result);
4193}
4194
4195static isc_result_t
4196reload(ns_server_t *server) {
4197	isc_result_t result;
4198	CHECK(loadconfig(server));
4199
4200	result = load_zones(server, ISC_FALSE);
4201	if (result == ISC_R_SUCCESS)
4202		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4203			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4204			      "reloading zones succeeded");
4205	else
4206		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4207			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4208			      "reloading zones failed: %s",
4209			      isc_result_totext(result));
4210
4211 cleanup:
4212	return (result);
4213}
4214
4215static void
4216reconfig(ns_server_t *server) {
4217	isc_result_t result;
4218	CHECK(loadconfig(server));
4219
4220	result = load_new_zones(server, ISC_FALSE);
4221	if (result == ISC_R_SUCCESS)
4222		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4223			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4224			      "any newly configured zones are now loaded");
4225	else
4226		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4227			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4228			      "loading new zones failed: %s",
4229			      isc_result_totext(result));
4230
4231 cleanup: ;
4232}
4233
4234/*
4235 * Handle a reload event (from SIGHUP).
4236 */
4237static void
4238ns_server_reload(isc_task_t *task, isc_event_t *event) {
4239	ns_server_t *server = (ns_server_t *)event->ev_arg;
4240
4241	INSIST(task = server->task);
4242	UNUSED(task);
4243
4244	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4245		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4246		      "received SIGHUP signal to reload zones");
4247	(void)reload(server);
4248
4249	LOCK(&server->reload_event_lock);
4250	INSIST(server->reload_event == NULL);
4251	server->reload_event = event;
4252	UNLOCK(&server->reload_event_lock);
4253}
4254
4255void
4256ns_server_reloadwanted(ns_server_t *server) {
4257	LOCK(&server->reload_event_lock);
4258	if (server->reload_event != NULL)
4259		isc_task_send(server->task, &server->reload_event);
4260	UNLOCK(&server->reload_event_lock);
4261}
4262
4263static char *
4264next_token(char **stringp, const char *delim) {
4265	char *res;
4266
4267	do {
4268		res = strsep(stringp, delim);
4269		if (res == NULL)
4270			break;
4271	} while (*res == '\0');
4272	return (res);
4273}
4274
4275/*
4276 * Find the zone specified in the control channel command 'args',
4277 * if any.  If a zone is specified, point '*zonep' at it, otherwise
4278 * set '*zonep' to NULL.
4279 */
4280static isc_result_t
4281zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
4282	char *input, *ptr;
4283	const char *zonetxt;
4284	char *classtxt;
4285	const char *viewtxt = NULL;
4286	dns_fixedname_t name;
4287	isc_result_t result;
4288	isc_buffer_t buf;
4289	dns_view_t *view = NULL;
4290	dns_rdataclass_t rdclass;
4291
4292	REQUIRE(zonep != NULL && *zonep == NULL);
4293
4294	input = args;
4295
4296	/* Skip the command name. */
4297	ptr = next_token(&input, " \t");
4298	if (ptr == NULL)
4299		return (ISC_R_UNEXPECTEDEND);
4300
4301	/* Look for the zone name. */
4302	zonetxt = next_token(&input, " \t");
4303	if (zonetxt == NULL)
4304		return (ISC_R_SUCCESS);
4305
4306	/* Look for the optional class name. */
4307	classtxt = next_token(&input, " \t");
4308	if (classtxt != NULL) {
4309		/* Look for the optional view name. */
4310		viewtxt = next_token(&input, " \t");
4311	}
4312
4313	isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
4314	isc_buffer_add(&buf, strlen(zonetxt));
4315	dns_fixedname_init(&name);
4316	result = dns_name_fromtext(dns_fixedname_name(&name),
4317				   &buf, dns_rootname, ISC_FALSE, NULL);
4318	if (result != ISC_R_SUCCESS)
4319		goto fail1;
4320
4321	if (classtxt != NULL) {
4322		isc_textregion_t r;
4323		r.base = classtxt;
4324		r.length = strlen(classtxt);
4325		result = dns_rdataclass_fromtext(&rdclass, &r);
4326		if (result != ISC_R_SUCCESS)
4327			goto fail1;
4328	} else
4329		rdclass = dns_rdataclass_in;
4330
4331	if (viewtxt == NULL) {
4332		result = dns_viewlist_findzone(&server->viewlist,
4333					       dns_fixedname_name(&name),
4334					       ISC_TF(classtxt == NULL),
4335					       rdclass, zonep);
4336	} else {
4337		result = dns_viewlist_find(&server->viewlist, viewtxt,
4338					   rdclass, &view);
4339		if (result != ISC_R_SUCCESS)
4340			goto fail1;
4341
4342		result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
4343				     0, NULL, zonep);
4344		dns_view_detach(&view);
4345	}
4346
4347	/* Partial match? */
4348	if (result != ISC_R_SUCCESS && *zonep != NULL)
4349		dns_zone_detach(zonep);
4350	if (result == DNS_R_PARTIALMATCH)
4351		result = ISC_R_NOTFOUND;
4352 fail1:
4353	return (result);
4354}
4355
4356/*
4357 * Act on a "retransfer" command from the command channel.
4358 */
4359isc_result_t
4360ns_server_retransfercommand(ns_server_t *server, char *args) {
4361	isc_result_t result;
4362	dns_zone_t *zone = NULL;
4363	dns_zonetype_t type;
4364
4365	result = zone_from_args(server, args, &zone);
4366	if (result != ISC_R_SUCCESS)
4367		return (result);
4368	if (zone == NULL)
4369		return (ISC_R_UNEXPECTEDEND);
4370	type = dns_zone_gettype(zone);
4371	if (type == dns_zone_slave || type == dns_zone_stub)
4372		dns_zone_forcereload(zone);
4373	else
4374		result = ISC_R_NOTFOUND;
4375	dns_zone_detach(&zone);
4376	return (result);
4377}
4378
4379/*
4380 * Act on a "reload" command from the command channel.
4381 */
4382isc_result_t
4383ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4384	isc_result_t result;
4385	dns_zone_t *zone = NULL;
4386	dns_zonetype_t type;
4387	const char *msg = NULL;
4388
4389	result = zone_from_args(server, args, &zone);
4390	if (result != ISC_R_SUCCESS)
4391		return (result);
4392	if (zone == NULL) {
4393		result = reload(server);
4394		if (result == ISC_R_SUCCESS)
4395			msg = "server reload successful";
4396	} else {
4397		type = dns_zone_gettype(zone);
4398		if (type == dns_zone_slave || type == dns_zone_stub) {
4399			dns_zone_refresh(zone);
4400			dns_zone_detach(&zone);
4401			msg = "zone refresh queued";
4402		} else {
4403			result = dns_zone_load(zone);
4404			dns_zone_detach(&zone);
4405			switch (result) {
4406			case ISC_R_SUCCESS:
4407				 msg = "zone reload successful";
4408				 break;
4409			case DNS_R_CONTINUE:
4410				msg = "zone reload queued";
4411				result = ISC_R_SUCCESS;
4412				break;
4413			case DNS_R_UPTODATE:
4414				msg = "zone reload up-to-date";
4415				result = ISC_R_SUCCESS;
4416				break;
4417			default:
4418				/* failure message will be generated by rndc */
4419				break;
4420			}
4421		}
4422	}
4423	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
4424		isc_buffer_putmem(text, (const unsigned char *)msg,
4425				  strlen(msg) + 1);
4426	return (result);
4427}
4428
4429/*
4430 * Act on a "reconfig" command from the command channel.
4431 */
4432isc_result_t
4433ns_server_reconfigcommand(ns_server_t *server, char *args) {
4434	UNUSED(args);
4435
4436	reconfig(server);
4437	return (ISC_R_SUCCESS);
4438}
4439
4440/*
4441 * Act on a "notify" command from the command channel.
4442 */
4443isc_result_t
4444ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4445	isc_result_t result;
4446	dns_zone_t *zone = NULL;
4447	const unsigned char msg[] = "zone notify queued";
4448
4449	result = zone_from_args(server, args, &zone);
4450	if (result != ISC_R_SUCCESS)
4451		return (result);
4452	if (zone == NULL)
4453		return (ISC_R_UNEXPECTEDEND);
4454
4455	dns_zone_notify(zone);
4456	dns_zone_detach(&zone);
4457	if (sizeof(msg) <= isc_buffer_availablelength(text))
4458		isc_buffer_putmem(text, msg, sizeof(msg));
4459
4460	return (ISC_R_SUCCESS);
4461}
4462
4463/*
4464 * Act on a "refresh" command from the command channel.
4465 */
4466isc_result_t
4467ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4468	isc_result_t result;
4469	dns_zone_t *zone = NULL;
4470	const unsigned char msg1[] = "zone refresh queued";
4471	const unsigned char msg2[] = "not a slave or stub zone";
4472	dns_zonetype_t type;
4473
4474	result = zone_from_args(server, args, &zone);
4475	if (result != ISC_R_SUCCESS)
4476		return (result);
4477	if (zone == NULL)
4478		return (ISC_R_UNEXPECTEDEND);
4479
4480	type = dns_zone_gettype(zone);
4481	if (type == dns_zone_slave || type == dns_zone_stub) {
4482		dns_zone_refresh(zone);
4483		dns_zone_detach(&zone);
4484		if (sizeof(msg1) <= isc_buffer_availablelength(text))
4485			isc_buffer_putmem(text, msg1, sizeof(msg1));
4486		return (ISC_R_SUCCESS);
4487	}
4488
4489	dns_zone_detach(&zone);
4490	if (sizeof(msg2) <= isc_buffer_availablelength(text))
4491		isc_buffer_putmem(text, msg2, sizeof(msg2));
4492	return (ISC_R_FAILURE);
4493}
4494
4495isc_result_t
4496ns_server_togglequerylog(ns_server_t *server) {
4497	server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
4498
4499	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4500		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4501		      "query logging is now %s",
4502		      server->log_queries ? "on" : "off");
4503	return (ISC_R_SUCCESS);
4504}
4505
4506static isc_result_t
4507ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
4508			 cfg_aclconfctx_t *actx,
4509			 isc_mem_t *mctx, ns_listenlist_t **target)
4510{
4511	isc_result_t result;
4512	const cfg_listelt_t *element;
4513	ns_listenlist_t *dlist = NULL;
4514
4515	REQUIRE(target != NULL && *target == NULL);
4516
4517	result = ns_listenlist_create(mctx, &dlist);
4518	if (result != ISC_R_SUCCESS)
4519		return (result);
4520
4521	for (element = cfg_list_first(listenlist);
4522	     element != NULL;
4523	     element = cfg_list_next(element))
4524	{
4525		ns_listenelt_t *delt = NULL;
4526		const cfg_obj_t *listener = cfg_listelt_value(element);
4527		result = ns_listenelt_fromconfig(listener, config, actx,
4528						 mctx, &delt);
4529		if (result != ISC_R_SUCCESS)
4530			goto cleanup;
4531		ISC_LIST_APPEND(dlist->elts, delt, link);
4532	}
4533	*target = dlist;
4534	return (ISC_R_SUCCESS);
4535
4536 cleanup:
4537	ns_listenlist_detach(&dlist);
4538	return (result);
4539}
4540
4541/*
4542 * Create a listen list from the corresponding configuration
4543 * data structure.
4544 */
4545static isc_result_t
4546ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
4547			cfg_aclconfctx_t *actx,
4548			isc_mem_t *mctx, ns_listenelt_t **target)
4549{
4550	isc_result_t result;
4551	const cfg_obj_t *portobj;
4552	in_port_t port;
4553	ns_listenelt_t *delt = NULL;
4554	REQUIRE(target != NULL && *target == NULL);
4555
4556	portobj = cfg_tuple_get(listener, "port");
4557	if (!cfg_obj_isuint32(portobj)) {
4558		if (ns_g_port != 0) {
4559			port = ns_g_port;
4560		} else {
4561			result = ns_config_getport(config, &port);
4562			if (result != ISC_R_SUCCESS)
4563				return (result);
4564		}
4565	} else {
4566		if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
4567			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
4568				    "port value '%u' is out of range",
4569				    cfg_obj_asuint32(portobj));
4570			return (ISC_R_RANGE);
4571		}
4572		port = (in_port_t)cfg_obj_asuint32(portobj);
4573	}
4574
4575	result = ns_listenelt_create(mctx, port, NULL, &delt);
4576	if (result != ISC_R_SUCCESS)
4577		return (result);
4578
4579	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
4580				   config, ns_g_lctx, actx, mctx, 0,
4581				   &delt->acl);
4582	if (result != ISC_R_SUCCESS) {
4583		ns_listenelt_destroy(delt);
4584		return (result);
4585	}
4586	*target = delt;
4587	return (ISC_R_SUCCESS);
4588}
4589
4590isc_result_t
4591ns_server_dumpstats(ns_server_t *server) {
4592	isc_result_t result;
4593	FILE *fp = NULL;
4594
4595	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
4596		"could not open statistics dump file", server->statsfile);
4597
4598	result = ns_stats_dump(server, fp);
4599	CHECK(result);
4600
4601 cleanup:
4602	if (fp != NULL)
4603		(void)isc_stdio_close(fp);
4604	if (result == ISC_R_SUCCESS)
4605		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4606			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4607			      "dumpstats complete");
4608	else
4609		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4610			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4611			      "dumpstats failed: %s",
4612			      dns_result_totext(result));
4613	return (result);
4614}
4615
4616static isc_result_t
4617add_zone_tolist(dns_zone_t *zone, void *uap) {
4618	struct dumpcontext *dctx = uap;
4619	struct zonelistentry *zle;
4620
4621	zle = isc_mem_get(dctx->mctx, sizeof *zle);
4622	if (zle ==  NULL)
4623		return (ISC_R_NOMEMORY);
4624	zle->zone = NULL;
4625	dns_zone_attach(zone, &zle->zone);
4626	ISC_LINK_INIT(zle, link);
4627	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
4628	return (ISC_R_SUCCESS);
4629}
4630
4631static isc_result_t
4632add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
4633	struct viewlistentry *vle;
4634	isc_result_t result = ISC_R_SUCCESS;
4635
4636	/*
4637	 * Prevent duplicate views.
4638	 */
4639	for (vle = ISC_LIST_HEAD(dctx->viewlist);
4640	     vle != NULL;
4641	     vle = ISC_LIST_NEXT(vle, link))
4642		if (vle->view == view)
4643			return (ISC_R_SUCCESS);
4644
4645	vle = isc_mem_get(dctx->mctx, sizeof *vle);
4646	if (vle == NULL)
4647		return (ISC_R_NOMEMORY);
4648	vle->view = NULL;
4649	dns_view_attach(view, &vle->view);
4650	ISC_LINK_INIT(vle, link);
4651	ISC_LIST_INIT(vle->zonelist);
4652	ISC_LIST_APPEND(dctx->viewlist, vle, link);
4653	if (dctx->dumpzones)
4654		result = dns_zt_apply(view->zonetable, ISC_TRUE,
4655				      add_zone_tolist, dctx);
4656	return (result);
4657}
4658
4659static void
4660dumpcontext_destroy(struct dumpcontext *dctx) {
4661	struct viewlistentry *vle;
4662	struct zonelistentry *zle;
4663
4664	vle = ISC_LIST_HEAD(dctx->viewlist);
4665	while (vle != NULL) {
4666		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
4667		zle = ISC_LIST_HEAD(vle->zonelist);
4668		while (zle != NULL) {
4669			ISC_LIST_UNLINK(vle->zonelist, zle, link);
4670			dns_zone_detach(&zle->zone);
4671			isc_mem_put(dctx->mctx, zle, sizeof *zle);
4672			zle = ISC_LIST_HEAD(vle->zonelist);
4673		}
4674		dns_view_detach(&vle->view);
4675		isc_mem_put(dctx->mctx, vle, sizeof *vle);
4676		vle = ISC_LIST_HEAD(dctx->viewlist);
4677	}
4678	if (dctx->version != NULL)
4679		dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
4680	if (dctx->db != NULL)
4681		dns_db_detach(&dctx->db);
4682	if (dctx->cache != NULL)
4683		dns_db_detach(&dctx->cache);
4684	if (dctx->task != NULL)
4685		isc_task_detach(&dctx->task);
4686	if (dctx->fp != NULL)
4687		(void)isc_stdio_close(dctx->fp);
4688	if (dctx->mdctx != NULL)
4689		dns_dumpctx_detach(&dctx->mdctx);
4690	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
4691}
4692
4693static void
4694dumpdone(void *arg, isc_result_t result) {
4695	struct dumpcontext *dctx = arg;
4696	char buf[1024+32];
4697	const dns_master_style_t *style;
4698
4699	if (result != ISC_R_SUCCESS)
4700		goto cleanup;
4701	if (dctx->mdctx != NULL)
4702		dns_dumpctx_detach(&dctx->mdctx);
4703	if (dctx->view == NULL) {
4704		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
4705		if (dctx->view == NULL)
4706			goto done;
4707		INSIST(dctx->zone == NULL);
4708	} else
4709		goto resume;
4710 nextview:
4711	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
4712 resume:
4713	if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) {
4714		style = &dns_master_style_cache;
4715		/* start cache dump */
4716		if (dctx->view->view->cachedb != NULL)
4717			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
4718		if (dctx->cache != NULL) {
4719
4720			fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n",
4721				dctx->view->view->name);
4722			result = dns_master_dumptostreaminc(dctx->mctx,
4723							    dctx->cache, NULL,
4724							    style, dctx->fp,
4725							    dctx->task,
4726							    dumpdone, dctx,
4727							    &dctx->mdctx);
4728			if (result == DNS_R_CONTINUE)
4729				return;
4730			if (result == ISC_R_NOTIMPLEMENTED)
4731				fprintf(dctx->fp, "; %s\n",
4732					dns_result_totext(result));
4733			else if (result != ISC_R_SUCCESS)
4734				goto cleanup;
4735		}
4736	}
4737	if (dctx->cache != NULL) {
4738		dns_adb_dump(dctx->view->view->adb, dctx->fp);
4739		dns_resolver_printbadcache(dctx->view->view->resolver,
4740					   dctx->fp);
4741		dns_db_detach(&dctx->cache);
4742	}
4743	if (dctx->dumpzones) {
4744		style = &dns_master_style_full;
4745 nextzone:
4746		if (dctx->version != NULL)
4747			dns_db_closeversion(dctx->db, &dctx->version,
4748					    ISC_FALSE);
4749		if (dctx->db != NULL)
4750			dns_db_detach(&dctx->db);
4751		if (dctx->zone == NULL)
4752			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
4753		else
4754			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
4755		if (dctx->zone != NULL) {
4756			/* start zone dump */
4757			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
4758			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
4759			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
4760			if (result != ISC_R_SUCCESS) {
4761				fprintf(dctx->fp, "; %s\n",
4762					dns_result_totext(result));
4763				goto nextzone;
4764			}
4765			dns_db_currentversion(dctx->db, &dctx->version);
4766			result = dns_master_dumptostreaminc(dctx->mctx,
4767							    dctx->db,
4768							    dctx->version,
4769							    style, dctx->fp,
4770							    dctx->task,
4771							    dumpdone, dctx,
4772							    &dctx->mdctx);
4773			if (result == DNS_R_CONTINUE)
4774				return;
4775			if (result == ISC_R_NOTIMPLEMENTED) {
4776				fprintf(dctx->fp, "; %s\n",
4777					dns_result_totext(result));
4778				result = ISC_R_SUCCESS;
4779				goto nextzone;
4780			}
4781			if (result != ISC_R_SUCCESS)
4782				goto cleanup;
4783		}
4784	}
4785	if (dctx->view != NULL)
4786		dctx->view = ISC_LIST_NEXT(dctx->view, link);
4787	if (dctx->view != NULL)
4788		goto nextview;
4789 done:
4790	fprintf(dctx->fp, "; Dump complete\n");
4791	result = isc_stdio_flush(dctx->fp);
4792	if (result == ISC_R_SUCCESS)
4793		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4794			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4795			      "dumpdb complete");
4796 cleanup:
4797	if (result != ISC_R_SUCCESS)
4798		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4799			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4800			      "dumpdb failed: %s", dns_result_totext(result));
4801	dumpcontext_destroy(dctx);
4802}
4803
4804isc_result_t
4805ns_server_dumpdb(ns_server_t *server, char *args) {
4806	struct dumpcontext *dctx = NULL;
4807	dns_view_t *view;
4808	isc_result_t result;
4809	char *ptr;
4810	const char *sep;
4811
4812	/* Skip the command name. */
4813	ptr = next_token(&args, " \t");
4814	if (ptr == NULL)
4815		return (ISC_R_UNEXPECTEDEND);
4816
4817	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
4818	if (dctx == NULL)
4819		return (ISC_R_NOMEMORY);
4820
4821	dctx->mctx = server->mctx;
4822	dctx->dumpcache = ISC_TRUE;
4823	dctx->dumpzones = ISC_FALSE;
4824	dctx->fp = NULL;
4825	ISC_LIST_INIT(dctx->viewlist);
4826	dctx->view = NULL;
4827	dctx->zone = NULL;
4828	dctx->cache = NULL;
4829	dctx->mdctx = NULL;
4830	dctx->db = NULL;
4831	dctx->cache = NULL;
4832	dctx->task = NULL;
4833	dctx->version = NULL;
4834	isc_task_attach(server->task, &dctx->task);
4835
4836	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
4837		"could not open dump file", server->dumpfile);
4838
4839	sep = (args == NULL) ? "" : ": ";
4840	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4841		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4842		      "dumpdb started%s%s", sep, (args != NULL) ? args : "");
4843
4844	ptr = next_token(&args, " \t");
4845	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
4846		dctx->dumpzones = ISC_TRUE;
4847		dctx->dumpcache = ISC_TRUE;
4848		ptr = next_token(&args, " \t");
4849	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
4850		dctx->dumpzones = ISC_FALSE;
4851		dctx->dumpcache = ISC_TRUE;
4852		ptr = next_token(&args, " \t");
4853	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
4854		dctx->dumpzones = ISC_TRUE;
4855		dctx->dumpcache = ISC_FALSE;
4856		ptr = next_token(&args, " \t");
4857	}
4858
4859 nextview:
4860	for (view = ISC_LIST_HEAD(server->viewlist);
4861	     view != NULL;
4862	     view = ISC_LIST_NEXT(view, link))
4863	{
4864		if (ptr != NULL && strcmp(view->name, ptr) != 0)
4865			continue;
4866		CHECK(add_view_tolist(dctx, view));
4867	}
4868	if (ptr != NULL) {
4869		ptr = next_token(&args, " \t");
4870		if (ptr != NULL)
4871			goto nextview;
4872	}
4873	dumpdone(dctx, ISC_R_SUCCESS);
4874	return (ISC_R_SUCCESS);
4875
4876 cleanup:
4877	if (dctx != NULL)
4878		dumpcontext_destroy(dctx);
4879	return (result);
4880}
4881
4882isc_result_t
4883ns_server_dumprecursing(ns_server_t *server) {
4884	FILE *fp = NULL;
4885	isc_result_t result;
4886
4887	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
4888		"could not open dump file", server->recfile);
4889	fprintf(fp,";\n; Recursing Queries\n;\n");
4890	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
4891	fprintf(fp, "; Dump complete\n");
4892
4893 cleanup:
4894	if (fp != NULL)
4895		result = isc_stdio_close(fp);
4896	if (result == ISC_R_SUCCESS)
4897		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4898			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4899			      "dumprecursing complete");
4900	else
4901		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4902			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4903			      "dumprecursing failed: %s",
4904			      dns_result_totext(result));
4905	return (result);
4906}
4907
4908isc_result_t
4909ns_server_setdebuglevel(ns_server_t *server, char *args) {
4910	char *ptr;
4911	char *levelstr;
4912	char *endp;
4913	long newlevel;
4914
4915	UNUSED(server);
4916
4917	/* Skip the command name. */
4918	ptr = next_token(&args, " \t");
4919	if (ptr == NULL)
4920		return (ISC_R_UNEXPECTEDEND);
4921
4922	/* Look for the new level name. */
4923	levelstr = next_token(&args, " \t");
4924	if (levelstr == NULL) {
4925		if (ns_g_debuglevel < 99)
4926			ns_g_debuglevel++;
4927	} else {
4928		newlevel = strtol(levelstr, &endp, 10);
4929		if (*endp != '\0' || newlevel < 0 || newlevel > 99)
4930			return (ISC_R_RANGE);
4931		ns_g_debuglevel = (unsigned int)newlevel;
4932	}
4933	isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
4934	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4935		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4936		      "debug level is now %d", ns_g_debuglevel);
4937	return (ISC_R_SUCCESS);
4938}
4939
4940isc_result_t
4941ns_server_validation(ns_server_t *server, char *args) {
4942	char *ptr, *viewname;
4943	dns_view_t *view;
4944	isc_boolean_t changed = ISC_FALSE;
4945	isc_result_t result;
4946	isc_boolean_t enable;
4947
4948	/* Skip the command name. */
4949	ptr = next_token(&args, " \t");
4950	if (ptr == NULL)
4951		return (ISC_R_UNEXPECTEDEND);
4952
4953	/* Find out what we are to do. */
4954	ptr = next_token(&args, " \t");
4955	if (ptr == NULL)
4956		return (ISC_R_UNEXPECTEDEND);
4957
4958	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
4959	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
4960		enable = ISC_TRUE;
4961	else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
4962		 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
4963		enable = ISC_FALSE;
4964	else
4965		return (DNS_R_SYNTAX);
4966
4967	/* Look for the view name. */
4968	viewname = next_token(&args, " \t");
4969
4970	result = isc_task_beginexclusive(server->task);
4971	RUNTIME_CHECK(result == ISC_R_SUCCESS);
4972	for (view = ISC_LIST_HEAD(server->viewlist);
4973	     view != NULL;
4974	     view = ISC_LIST_NEXT(view, link))
4975	{
4976		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
4977			continue;
4978		result = dns_view_flushcache(view);
4979		if (result != ISC_R_SUCCESS)
4980			goto out;
4981		view->enablevalidation = enable;
4982		changed = ISC_TRUE;
4983	}
4984	if (changed)
4985		result = ISC_R_SUCCESS;
4986	else
4987		result = ISC_R_FAILURE;
4988 out:
4989	isc_task_endexclusive(server->task);
4990	return (result);
4991}
4992
4993isc_result_t
4994ns_server_flushcache(ns_server_t *server, char *args) {
4995	char *ptr, *viewname;
4996	dns_view_t *view;
4997	isc_boolean_t flushed;
4998	isc_boolean_t found;
4999	isc_result_t result;
5000
5001	/* Skip the command name. */
5002	ptr = next_token(&args, " \t");
5003	if (ptr == NULL)
5004		return (ISC_R_UNEXPECTEDEND);
5005
5006	/* Look for the view name. */
5007	viewname = next_token(&args, " \t");
5008
5009	result = isc_task_beginexclusive(server->task);
5010	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5011	flushed = ISC_TRUE;
5012	found = ISC_FALSE;
5013	for (view = ISC_LIST_HEAD(server->viewlist);
5014	     view != NULL;
5015	     view = ISC_LIST_NEXT(view, link))
5016	{
5017		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
5018			continue;
5019		found = ISC_TRUE;
5020		result = dns_view_flushcache(view);
5021		if (result != ISC_R_SUCCESS) {
5022			flushed = ISC_FALSE;
5023			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5024				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5025				      "flushing cache in view '%s' failed: %s",
5026				      view->name, isc_result_totext(result));
5027		}
5028	}
5029	if (flushed && found) {
5030		if (viewname != NULL)
5031			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5032				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5033				      "flushing cache in view '%s' succeeded",
5034				      viewname);
5035		else
5036			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5037				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5038				      "flushing caches in all views succeeded");
5039		result = ISC_R_SUCCESS;
5040	} else {
5041		if (!found) {
5042			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5043				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5044				      "flushing cache in view '%s' failed: "
5045				      "view not found", viewname);
5046			result = ISC_R_NOTFOUND;
5047		} else
5048			result = ISC_R_FAILURE;
5049	}
5050	isc_task_endexclusive(server->task);
5051	return (result);
5052}
5053
5054isc_result_t
5055ns_server_flushname(ns_server_t *server, char *args) {
5056	char *ptr, *target, *viewname;
5057	dns_view_t *view;
5058	isc_boolean_t flushed;
5059	isc_boolean_t found;
5060	isc_result_t result;
5061	isc_buffer_t b;
5062	dns_fixedname_t fixed;
5063	dns_name_t *name;
5064
5065	/* Skip the command name. */
5066	ptr = next_token(&args, " \t");
5067	if (ptr == NULL)
5068		return (ISC_R_UNEXPECTEDEND);
5069
5070	/* Find the domain name to flush. */
5071	target = next_token(&args, " \t");
5072	if (target == NULL)
5073		return (ISC_R_UNEXPECTEDEND);
5074
5075	isc_buffer_init(&b, target, strlen(target));
5076	isc_buffer_add(&b, strlen(target));
5077	dns_fixedname_init(&fixed);
5078	name = dns_fixedname_name(&fixed);
5079	result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
5080	if (result != ISC_R_SUCCESS)
5081		return (result);
5082
5083	/* Look for the view name. */
5084	viewname = next_token(&args, " \t");
5085
5086	result = isc_task_beginexclusive(server->task);
5087	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5088	flushed = ISC_TRUE;
5089	found = ISC_FALSE;
5090	for (view = ISC_LIST_HEAD(server->viewlist);
5091	     view != NULL;
5092	     view = ISC_LIST_NEXT(view, link))
5093	{
5094		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
5095			continue;
5096		found = ISC_TRUE;
5097		result = dns_view_flushname(view, name);
5098		if (result != ISC_R_SUCCESS) {
5099			flushed = ISC_FALSE;
5100			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5101				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5102				      "flushing name '%s' in cache view '%s' "
5103				      "failed: %s", target, view->name,
5104				      isc_result_totext(result));
5105		}
5106	}
5107	if (flushed && found) {
5108		if (viewname != NULL)
5109			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5110				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5111				      "flushing name '%s' in cache view '%s' "
5112				      "succeeded", target, viewname);
5113		else
5114			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5115				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5116				      "flushing name '%s' in all cache views "
5117				      "succeeded", target);
5118		result = ISC_R_SUCCESS;
5119	} else {
5120		if (!found)
5121			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5122				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5123				      "flushing name '%s' in cache view '%s' "
5124				      "failed: view not found", target,
5125				      viewname);
5126		result = ISC_R_FAILURE;
5127	}
5128	isc_task_endexclusive(server->task);
5129	return (result);
5130}
5131
5132isc_result_t
5133ns_server_status(ns_server_t *server, isc_buffer_t *text) {
5134	int zonecount, xferrunning, xferdeferred, soaqueries;
5135	unsigned int n;
5136	const char *ob = "", *cb = "", *alt = "";
5137
5138	if (ns_g_server->version_set) {
5139		ob = " (";
5140		cb = ")";
5141		if (ns_g_server->version == NULL)
5142			alt = "version.bind/txt/ch disabled";
5143		else
5144			alt = ns_g_server->version;
5145	}
5146	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
5147	xferrunning = dns_zonemgr_getcount(server->zonemgr,
5148					   DNS_ZONESTATE_XFERRUNNING);
5149	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
5150					    DNS_ZONESTATE_XFERDEFERRED);
5151	soaqueries = dns_zonemgr_getcount(server->zonemgr,
5152					  DNS_ZONESTATE_SOAQUERY);
5153
5154	n = snprintf((char *)isc_buffer_used(text),
5155		     isc_buffer_availablelength(text),
5156		     "version: %s%s%s%s\n"
5157#ifdef ISC_PLATFORM_USETHREADS
5158		     "CPUs found: %u\n"
5159		     "worker threads: %u\n"
5160#endif
5161		     "number of zones: %u\n"
5162		     "debug level: %d\n"
5163		     "xfers running: %u\n"
5164		     "xfers deferred: %u\n"
5165		     "soa queries in progress: %u\n"
5166		     "query logging is %s\n"
5167		     "recursive clients: %d/%d/%d\n"
5168		     "tcp clients: %d/%d\n"
5169		     "server is up and running",
5170		     ns_g_version, ob, alt, cb,
5171#ifdef ISC_PLATFORM_USETHREADS
5172		     ns_g_cpus_detected, ns_g_cpus,
5173#endif
5174		     zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
5175		     soaqueries, server->log_queries ? "ON" : "OFF",
5176		     server->recursionquota.used, server->recursionquota.soft,
5177		     server->recursionquota.max,
5178		     server->tcpquota.used, server->tcpquota.max);
5179	if (n >= isc_buffer_availablelength(text))
5180		return (ISC_R_NOSPACE);
5181	isc_buffer_add(text, n);
5182	return (ISC_R_SUCCESS);
5183}
5184
5185static isc_result_t
5186delete_keynames(dns_tsig_keyring_t *ring, char *target,
5187		unsigned int *foundkeys)
5188{
5189	char namestr[DNS_NAME_FORMATSIZE];
5190	isc_result_t result;
5191	dns_rbtnodechain_t chain;
5192	dns_name_t foundname;
5193	dns_fixedname_t fixedorigin;
5194	dns_name_t *origin;
5195	dns_rbtnode_t *node;
5196	dns_tsigkey_t *tkey;
5197
5198	dns_name_init(&foundname, NULL);
5199	dns_fixedname_init(&fixedorigin);
5200	origin = dns_fixedname_name(&fixedorigin);
5201
5202 again:
5203	dns_rbtnodechain_init(&chain, ring->mctx);
5204	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
5205					origin);
5206	if (result == ISC_R_NOTFOUND) {
5207		dns_rbtnodechain_invalidate(&chain);
5208		return (ISC_R_SUCCESS);
5209	}
5210	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
5211		dns_rbtnodechain_invalidate(&chain);
5212		return (result);
5213	}
5214
5215	for (;;) {
5216		node = NULL;
5217		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
5218		tkey = node->data;
5219
5220		if (tkey != NULL) {
5221			if (!tkey->generated)
5222				goto nextkey;
5223
5224			dns_name_format(&tkey->name, namestr, sizeof(namestr));
5225			if (strcmp(namestr, target) == 0) {
5226				(*foundkeys)++;
5227				dns_rbtnodechain_invalidate(&chain);
5228				(void)dns_rbt_deletename(ring->keys,
5229							 &tkey->name,
5230							 ISC_FALSE);
5231				goto again;
5232			}
5233		}
5234
5235	nextkey:
5236		result = dns_rbtnodechain_next(&chain, &foundname, origin);
5237		if (result == ISC_R_NOMORE)
5238			break;
5239		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
5240			dns_rbtnodechain_invalidate(&chain);
5241			return (result);
5242		}
5243	}
5244
5245	return (ISC_R_SUCCESS);
5246}
5247
5248isc_result_t
5249ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
5250	isc_result_t result;
5251	unsigned int n;
5252	dns_view_t *view;
5253	unsigned int foundkeys = 0;
5254	char *target;
5255	char *viewname;
5256
5257	(void)next_token(&command, " \t");  /* skip command name */
5258	target = next_token(&command, " \t");
5259	if (target == NULL)
5260		return (ISC_R_UNEXPECTEDEND);
5261	viewname = next_token(&command, " \t");
5262
5263	result = isc_task_beginexclusive(server->task);
5264	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5265	for (view = ISC_LIST_HEAD(server->viewlist);
5266	     view != NULL;
5267	     view = ISC_LIST_NEXT(view, link)) {
5268		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
5269			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
5270			result = delete_keynames(view->dynamickeys, target,
5271						 &foundkeys);
5272			RWUNLOCK(&view->dynamickeys->lock,
5273				 isc_rwlocktype_write);
5274			if (result != ISC_R_SUCCESS) {
5275				isc_task_endexclusive(server->task);
5276				return (result);
5277			}
5278		}
5279	}
5280	isc_task_endexclusive(server->task);
5281
5282	n = snprintf((char *)isc_buffer_used(text),
5283		     isc_buffer_availablelength(text),
5284		     "%d tsig keys deleted.\n", foundkeys);
5285	if (n >= isc_buffer_availablelength(text))
5286		return (ISC_R_NOSPACE);
5287	isc_buffer_add(text, n);
5288
5289	return (ISC_R_SUCCESS);
5290}
5291
5292static isc_result_t
5293list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
5294	     unsigned int *foundkeys)
5295{
5296	char namestr[DNS_NAME_FORMATSIZE];
5297	char creatorstr[DNS_NAME_FORMATSIZE];
5298	isc_result_t result;
5299	dns_rbtnodechain_t chain;
5300	dns_name_t foundname;
5301	dns_fixedname_t fixedorigin;
5302	dns_name_t *origin;
5303	dns_rbtnode_t *node;
5304	dns_tsigkey_t *tkey;
5305	unsigned int n;
5306	const char *viewname;
5307
5308	if (view != NULL)
5309		viewname = view->name;
5310	else
5311		viewname = "(global)";
5312
5313	dns_name_init(&foundname, NULL);
5314	dns_fixedname_init(&fixedorigin);
5315	origin = dns_fixedname_name(&fixedorigin);
5316	dns_rbtnodechain_init(&chain, ring->mctx);
5317	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
5318					origin);
5319	if (result == ISC_R_NOTFOUND) {
5320		dns_rbtnodechain_invalidate(&chain);
5321		return (ISC_R_SUCCESS);
5322	}
5323	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
5324		dns_rbtnodechain_invalidate(&chain);
5325		return (result);
5326	}
5327
5328	for (;;) {
5329		node = NULL;
5330		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
5331		tkey = node->data;
5332
5333		if (tkey != NULL) {
5334			(*foundkeys)++;
5335			dns_name_format(&tkey->name, namestr, sizeof(namestr));
5336			if (tkey->generated) {
5337				dns_name_format(tkey->creator, creatorstr,
5338						sizeof(creatorstr));
5339				n = snprintf((char *)isc_buffer_used(text),
5340					     isc_buffer_availablelength(text),
5341					     "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
5342					     viewname, namestr, creatorstr);
5343			} else {
5344				n = snprintf((char *)isc_buffer_used(text),
5345					     isc_buffer_availablelength(text),
5346					     "view \"%s\"; type \"static\"; key \"%s\";\n",
5347					     viewname, namestr);
5348			}
5349			if (n >= isc_buffer_availablelength(text)) {
5350				dns_rbtnodechain_invalidate(&chain);
5351				return (ISC_R_NOSPACE);
5352			}
5353			isc_buffer_add(text, n);
5354		}
5355		result = dns_rbtnodechain_next(&chain, &foundname, origin);
5356		if (result == ISC_R_NOMORE)
5357			break;
5358		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
5359			dns_rbtnodechain_invalidate(&chain);
5360			return (result);
5361		}
5362	}
5363
5364	return (ISC_R_SUCCESS);
5365}
5366
5367isc_result_t
5368ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
5369	isc_result_t result;
5370	unsigned int n;
5371	dns_view_t *view;
5372	unsigned int foundkeys = 0;
5373
5374	result = isc_task_beginexclusive(server->task);
5375	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5376	for (view = ISC_LIST_HEAD(server->viewlist);
5377	     view != NULL;
5378	     view = ISC_LIST_NEXT(view, link)) {
5379		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
5380		result = list_keynames(view, view->statickeys, text,
5381				       &foundkeys);
5382		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
5383		if (result != ISC_R_SUCCESS) {
5384			isc_task_endexclusive(server->task);
5385			return (result);
5386		}
5387		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
5388		result = list_keynames(view, view->dynamickeys, text,
5389				       &foundkeys);
5390		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
5391		if (result != ISC_R_SUCCESS) {
5392			isc_task_endexclusive(server->task);
5393			return (result);
5394		}
5395	}
5396	isc_task_endexclusive(server->task);
5397
5398	if (foundkeys == 0) {
5399		n = snprintf((char *)isc_buffer_used(text),
5400			     isc_buffer_availablelength(text),
5401			     "no tsig keys found.\n");
5402		if (n >= isc_buffer_availablelength(text))
5403			return (ISC_R_NOSPACE);
5404		isc_buffer_add(text, n);
5405	}
5406
5407	return (ISC_R_SUCCESS);
5408}
5409
5410/*
5411 * Act on a "freeze" or "thaw" command from the command channel.
5412 */
5413isc_result_t
5414ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
5415		 isc_buffer_t *text)
5416{
5417	isc_result_t result, tresult;
5418	dns_zone_t *zone = NULL;
5419	dns_zonetype_t type;
5420	char classstr[DNS_RDATACLASS_FORMATSIZE];
5421	char zonename[DNS_NAME_FORMATSIZE];
5422	dns_view_t *view;
5423	char *journal;
5424	const char *vname, *sep;
5425	isc_boolean_t frozen;
5426	const char *msg = NULL;
5427
5428	result = zone_from_args(server, args, &zone);
5429	if (result != ISC_R_SUCCESS)
5430		return (result);
5431	if (zone == NULL) {
5432		result = isc_task_beginexclusive(server->task);
5433		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5434		tresult = ISC_R_SUCCESS;
5435		for (view = ISC_LIST_HEAD(server->viewlist);
5436		     view != NULL;
5437		     view = ISC_LIST_NEXT(view, link)) {
5438			result = dns_view_freezezones(view, freeze);
5439			if (result != ISC_R_SUCCESS &&
5440			    tresult == ISC_R_SUCCESS)
5441				tresult = result;
5442		}
5443		isc_task_endexclusive(server->task);
5444		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5445			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5446			      "%s all zones: %s",
5447			      freeze ? "freezing" : "thawing",
5448			      isc_result_totext(tresult));
5449		return (tresult);
5450	}
5451	type = dns_zone_gettype(zone);
5452	if (type != dns_zone_master) {
5453		dns_zone_detach(&zone);
5454		return (ISC_R_NOTFOUND);
5455	}
5456
5457	result = isc_task_beginexclusive(server->task);
5458	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5459	frozen = dns_zone_getupdatedisabled(zone);
5460	if (freeze) {
5461		if (frozen) {
5462			msg = "WARNING: The zone was already frozen.\n"
5463			      "Someone else may be editing it or "
5464			      "it may still be re-loading.";
5465			result = DNS_R_FROZEN;
5466		}
5467		if (result == ISC_R_SUCCESS) {
5468			result = dns_zone_flush(zone);
5469			if (result != ISC_R_SUCCESS)
5470				msg = "Flushing the zone updates to "
5471				      "disk failed.";
5472		}
5473		if (result == ISC_R_SUCCESS) {
5474			journal = dns_zone_getjournal(zone);
5475			if (journal != NULL)
5476				(void)isc_file_remove(journal);
5477		}
5478		if (result == ISC_R_SUCCESS)
5479			dns_zone_setupdatedisabled(zone, freeze);
5480	} else {
5481		if (frozen) {
5482			result = dns_zone_loadandthaw(zone);
5483			switch (result) {
5484			case ISC_R_SUCCESS:
5485			case DNS_R_UPTODATE:
5486				msg = "The zone reload and thaw was "
5487				      "successful.";
5488				result = ISC_R_SUCCESS;
5489				break;
5490			case DNS_R_CONTINUE:
5491				msg = "A zone reload and thaw was started.\n"
5492				      "Check the logs to see the result.";
5493				result = ISC_R_SUCCESS;
5494				break;
5495			}
5496		}
5497	}
5498	isc_task_endexclusive(server->task);
5499
5500	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
5501		isc_buffer_putmem(text, (const unsigned char *)msg,
5502				  strlen(msg) + 1);
5503
5504	view = dns_zone_getview(zone);
5505	if (strcmp(view->name, "_bind") == 0 ||
5506	    strcmp(view->name, "_default") == 0)
5507	{
5508		vname = "";
5509		sep = "";
5510	} else {
5511		vname = view->name;
5512		sep = " ";
5513	}
5514	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
5515			      sizeof(classstr));
5516	dns_name_format(dns_zone_getorigin(zone),
5517			zonename, sizeof(zonename));
5518	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5519		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5520		      "%s zone '%s/%s'%s%s: %s",
5521		      freeze ? "freezing" : "thawing",
5522		      zonename, classstr, sep, vname,
5523		      isc_result_totext(result));
5524	dns_zone_detach(&zone);
5525	return (result);
5526}
5527
5528#ifdef HAVE_LIBSCF
5529/*
5530 * This function adds a message for rndc to echo if named
5531 * is managed by smf and is also running chroot.
5532 */
5533isc_result_t
5534ns_smf_add_message(isc_buffer_t *text) {
5535	unsigned int n;
5536
5537	n = snprintf((char *)isc_buffer_used(text),
5538		isc_buffer_availablelength(text),
5539		"use svcadm(1M) to manage named");
5540	if (n >= isc_buffer_availablelength(text))
5541		return (ISC_R_NOSPACE);
5542	isc_buffer_add(text, n);
5543	return (ISC_R_SUCCESS);
5544}
5545#endif /* HAVE_LIBSCF */
5546