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