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