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