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