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