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