1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2001-2003  Internet Software Consortium.
4135446Strhodes *
5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18170222Sdougb/*! \file */
19170222Sdougb
20135446Strhodes#include <config.h>
21135446Strhodes
22135446Strhodes#include <stdlib.h>
23135446Strhodes
24135446Strhodes#include <isc/buffer.h>
25135446Strhodes#include <isc/log.h>
26135446Strhodes#include <isc/mem.h>
27170222Sdougb#include <isc/parseint.h>
28135446Strhodes#include <isc/region.h>
29135446Strhodes#include <isc/result.h>
30135446Strhodes#include <isc/sockaddr.h>
31174187Sdougb#include <isc/string.h>
32135446Strhodes#include <isc/util.h>
33135446Strhodes
34135446Strhodes#include <isccfg/namedconf.h>
35135446Strhodes
36135446Strhodes#include <dns/fixedname.h>
37135446Strhodes#include <dns/name.h>
38135446Strhodes#include <dns/rdataclass.h>
39135446Strhodes#include <dns/rdatatype.h>
40135446Strhodes#include <dns/tsig.h>
41135446Strhodes#include <dns/zone.h>
42135446Strhodes
43224092Sdougb#include <dst/dst.h>
44224092Sdougb
45135446Strhodes#include <named/config.h>
46135446Strhodes#include <named/globals.h>
47135446Strhodes
48224092Sdougb#include "bind.keys.h"
49224092Sdougb
50170222Sdougb/*% default configuration */
51135446Strhodesstatic char defaultconf[] = "\
52135446Strhodesoptions {\n\
53135446Strhodes#	blackhole {none;};\n"
54135446Strhodes#ifndef WIN32
55135446Strhodes"	coresize default;\n\
56135446Strhodes	datasize default;\n\
57182645Sdougb	files unlimited;\n\
58135446Strhodes	stacksize default;\n"
59135446Strhodes#endif
60224092Sdougb"#	session-keyfile \"" NS_LOCALSTATEDIR "/run/named/session.key\";\n\
61224092Sdougb	session-keyname local-ddns;\n\
62224092Sdougb	session-keyalg hmac-sha256;\n\
63224092Sdougb	deallocate-on-exit true;\n\
64135446Strhodes#	directory <none>\n\
65135446Strhodes	dump-file \"named_dump.db\";\n\
66135446Strhodes	fake-iquery no;\n\
67135446Strhodes	has-old-clients false;\n\
68135446Strhodes	heartbeat-interval 60;\n\
69135446Strhodes	host-statistics no;\n\
70135446Strhodes	interface-interval 60;\n\
71135446Strhodes	listen-on {any;};\n\
72135446Strhodes	listen-on-v6 {none;};\n\
73135446Strhodes	match-mapped-addresses no;\n\
74254897Serwin	max-rsa-exponent-size 0; /* no limit */\n\
75135446Strhodes	memstatistics-file \"named.memstats\";\n\
76135446Strhodes	multiple-cnames no;\n\
77135446Strhodes#	named-xfer <obsolete>;\n\
78193149Sdougb#	pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
79224092Sdougb	bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
80135446Strhodes	port 53;\n\
81135446Strhodes	recursing-file \"named.recursing\";\n\
82224092Sdougb	secroots-file \"named.secroots\";\n\
83135446Strhodes"
84135446Strhodes#ifdef PATH_RANDOMDEV
85135446Strhodes"\
86135446Strhodes	random-device \"" PATH_RANDOMDEV "\";\n\
87135446Strhodes"
88135446Strhodes#endif
89135446Strhodes"\
90135446Strhodes	recursive-clients 1000;\n\
91245163Serwin	resolver-query-timeout 10;\n\
92254897Serwin	rrset-order { order random; };\n\
93135446Strhodes	serial-queries 20;\n\
94135446Strhodes	serial-query-rate 20;\n\
95135446Strhodes	server-id none;\n\
96135446Strhodes	statistics-file \"named.stats\";\n\
97135446Strhodes	statistics-interval 60;\n\
98135446Strhodes	tcp-clients 100;\n\
99262706Serwin	tcp-listen-queue 10;\n\
100135446Strhodes#	tkey-dhkey <none>\n\
101135446Strhodes#	tkey-gssapi-credential <none>\n\
102135446Strhodes#	tkey-domain <none>\n\
103135446Strhodes	transfers-per-ns 2;\n\
104135446Strhodes	transfers-in 10;\n\
105135446Strhodes	transfers-out 10;\n\
106135446Strhodes	treat-cr-as-space true;\n\
107135446Strhodes	use-id-pool true;\n\
108135446Strhodes	use-ixfr true;\n\
109135446Strhodes	edns-udp-size 4096;\n\
110170222Sdougb	max-udp-size 4096;\n\
111193149Sdougb	request-nsid false;\n\
112182645Sdougb	reserved-sockets 512;\n\
113135446Strhodes\n\
114224092Sdougb	/* DLV */\n\
115224092Sdougb	dnssec-lookaside . trust-anchor dlv.isc.org;\n\
116224092Sdougb\n\
117135446Strhodes	/* view */\n\
118135446Strhodes	allow-notify {none;};\n\
119135446Strhodes	allow-update-forwarding {none;};\n\
120170222Sdougb	allow-query-cache { localnets; localhost; };\n\
121193149Sdougb	allow-query-cache-on { any; };\n\
122170222Sdougb	allow-recursion { localnets; localhost; };\n\
123193149Sdougb	allow-recursion-on { any; };\n\
124135446Strhodes#	allow-v6-synthesis <obsolete>;\n\
125135446Strhodes#	sortlist <none>\n\
126135446Strhodes#	topology <none>\n\
127135446Strhodes	auth-nxdomain false;\n\
128135446Strhodes	minimal-responses false;\n\
129135446Strhodes	recursion true;\n\
130135446Strhodes	provide-ixfr true;\n\
131135446Strhodes	request-ixfr true;\n\
132135446Strhodes	fetch-glue no;\n\
133135446Strhodes	rfc2308-type1 no;\n\
134135446Strhodes	additional-from-auth true;\n\
135135446Strhodes	additional-from-cache true;\n\
136135446Strhodes	query-source address *;\n\
137135446Strhodes	query-source-v6 address *;\n\
138135446Strhodes	notify-source *;\n\
139135446Strhodes	notify-source-v6 *;\n\
140193149Sdougb	cleaning-interval 0;  /* now meaningless */\n\
141135446Strhodes	min-roots 2;\n\
142135446Strhodes	lame-ttl 600;\n\
143135446Strhodes	max-ncache-ttl 10800; /* 3 hours */\n\
144135446Strhodes	max-cache-ttl 604800; /* 1 week */\n\
145135446Strhodes	transfer-format many-answers;\n\
146135446Strhodes	max-cache-size 0;\n\
147135446Strhodes	check-names master fail;\n\
148135446Strhodes	check-names slave warn;\n\
149135446Strhodes	check-names response ignore;\n\
150224092Sdougb	check-dup-records warn;\n\
151170222Sdougb	check-mx warn;\n\
152254402Serwin	check-spf warn;\n\
153170222Sdougb	acache-enable no;\n\
154170222Sdougb	acache-cleaning-interval 60;\n\
155193149Sdougb	max-acache-size 16M;\n\
156170222Sdougb	dnssec-enable yes;\n\
157193149Sdougb	dnssec-validation yes; \n\
158170222Sdougb	dnssec-accept-expired no;\n\
159170222Sdougb	clients-per-query 10;\n\
160170222Sdougb	max-clients-per-query 100;\n\
161275672Sdelphij	max-recursion-depth 7;\n\
162170222Sdougb	zero-no-soa-ttl-cache no;\n\
163193149Sdougb	nsec3-test-zone no;\n\
164224092Sdougb	allow-new-zones no;\n\
165135446Strhodes"
166224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4
167224092Sdougb"	filter-aaaa-on-v4 no;\n\
168224092Sdougb	filter-aaaa { any; };\n\
169224092Sdougb"
170224092Sdougb#endif
171135446Strhodes
172135446Strhodes"	/* zone */\n\
173135446Strhodes	allow-query {any;};\n\
174193149Sdougb	allow-query-on {any;};\n\
175135446Strhodes	allow-transfer {any;};\n\
176135446Strhodes	notify yes;\n\
177135446Strhodes#	also-notify <none>\n\
178170222Sdougb	notify-delay 5;\n\
179193149Sdougb	notify-to-soa no;\n\
180135446Strhodes	dialup no;\n\
181135446Strhodes#	forward <none>\n\
182135446Strhodes#	forwarders <none>\n\
183135446Strhodes	maintain-ixfr-base no;\n\
184135446Strhodes#	max-ixfr-log-size <obsolete>\n\
185135446Strhodes	transfer-source *;\n\
186135446Strhodes	transfer-source-v6 *;\n\
187135446Strhodes	alt-transfer-source *;\n\
188135446Strhodes	alt-transfer-source-v6 *;\n\
189135446Strhodes	max-transfer-time-in 120;\n\
190135446Strhodes	max-transfer-time-out 120;\n\
191135446Strhodes	max-transfer-idle-in 60;\n\
192135446Strhodes	max-transfer-idle-out 60;\n\
193135446Strhodes	max-retry-time 1209600; /* 2 weeks */\n\
194135446Strhodes	min-retry-time 500;\n\
195135446Strhodes	max-refresh-time 2419200; /* 4 weeks */\n\
196135446Strhodes	min-refresh-time 300;\n\
197135446Strhodes	multi-master no;\n\
198224092Sdougb	dnssec-secure-to-insecure no;\n\
199135446Strhodes	sig-validity-interval 30; /* days */\n\
200193149Sdougb	sig-signing-nodes 100;\n\
201193149Sdougb	sig-signing-signatures 10;\n\
202193149Sdougb	sig-signing-type 65534;\n\
203254897Serwin	inline-signing no;\n\
204254897Serwin	zone-statistics terse;\n\
205135446Strhodes	max-journal-size unlimited;\n\
206135446Strhodes	ixfr-from-differences false;\n\
207170222Sdougb	check-wildcard yes;\n\
208170222Sdougb	check-sibling yes;\n\
209170222Sdougb	check-integrity yes;\n\
210170222Sdougb	check-mx-cname warn;\n\
211170222Sdougb	check-srv-cname warn;\n\
212170222Sdougb	zero-no-soa-ttl yes;\n\
213170222Sdougb	update-check-ksk yes;\n\
214254897Serwin	serial-update-method increment;\n\
215254897Serwin	dnssec-update-mode maintain;\n\
216224092Sdougb	dnssec-dnskey-kskonly no;\n\
217254897Serwin	dnssec-loadkeys-interval 60;\n\
218193149Sdougb	try-tcp-refresh yes; /* BIND 8 compat */\n\
219135446Strhodes};\n\
220135446Strhodes"
221135446Strhodes
222135446Strhodes"#\n\
223174187Sdougb#  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
224135446Strhodes#\n\
225135446Strhodesview \"_bind\" chaos {\n\
226135446Strhodes	recursion no;\n\
227135446Strhodes	notify no;\n\
228224092Sdougb	allow-new-zones no;\n\
229262706Serwin"
230262706Serwin#ifdef USE_RRL
231262706Serwin"	# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
232262706Serwin	rate-limit {\n\
233262706Serwin		responses-per-second 3;\n\
234262706Serwin		slip 0;\n\
235262706Serwin		min-table-size 10;\n\
236262706Serwin	};\n\
237262706Serwin"
238262706Serwin#endif /* USE_RRL */
239262706Serwin"	zone \"version.bind\" chaos {\n\
240135446Strhodes		type master;\n\
241135446Strhodes		database \"_builtin version\";\n\
242135446Strhodes	};\n\
243135446Strhodes\n\
244135446Strhodes	zone \"hostname.bind\" chaos {\n\
245135446Strhodes		type master;\n\
246135446Strhodes		database \"_builtin hostname\";\n\
247135446Strhodes	};\n\
248135446Strhodes\n\
249135446Strhodes	zone \"authors.bind\" chaos {\n\
250135446Strhodes		type master;\n\
251135446Strhodes		database \"_builtin authors\";\n\
252135446Strhodes	};\n\
253224092Sdougb\n\
254135446Strhodes	zone \"id.server\" chaos {\n\
255135446Strhodes		type master;\n\
256135446Strhodes		database \"_builtin id\";\n\
257135446Strhodes	};\n\
258135446Strhodes};\n\
259224092Sdougb"
260224092Sdougb"#\n\
261224092Sdougb#  Default trusted key(s) for builtin DLV support\n\
262224092Sdougb#  (used if \"dnssec-lookaside auto;\" is set and\n\
263224092Sdougb#  sysconfdir/bind.keys doesn't exist).\n\
264224092Sdougb#\n\
265224092Sdougb# BEGIN MANAGED KEYS\n"
266224092Sdougb
267224092Sdougb/* Imported from bind.keys.h: */
268224092SdougbMANAGED_KEYS
269224092Sdougb
270224092Sdougb"# END MANAGED KEYS\n\
271135446Strhodes";
272135446Strhodes
273135446Strhodesisc_result_t
274135446Strhodesns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
275135446Strhodes	isc_buffer_t b;
276135446Strhodes
277135446Strhodes	isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1);
278135446Strhodes	isc_buffer_add(&b, sizeof(defaultconf) - 1);
279135446Strhodes	return (cfg_parse_buffer(parser, &b, &cfg_type_namedconf, conf));
280135446Strhodes}
281135446Strhodes
282135446Strhodesisc_result_t
283165071Sdougbns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
284135446Strhodes	int i;
285135446Strhodes
286135446Strhodes	for (i = 0;; i++) {
287135446Strhodes		if (maps[i] == NULL)
288135446Strhodes			return (ISC_R_NOTFOUND);
289135446Strhodes		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
290135446Strhodes			return (ISC_R_SUCCESS);
291135446Strhodes	}
292135446Strhodes}
293135446Strhodes
294135446Strhodesisc_result_t
295165071Sdougbns_checknames_get(const cfg_obj_t **maps, const char *which,
296165071Sdougb		  const cfg_obj_t **obj)
297165071Sdougb{
298165071Sdougb	const cfg_listelt_t *element;
299165071Sdougb	const cfg_obj_t *checknames;
300165071Sdougb	const cfg_obj_t *type;
301165071Sdougb	const cfg_obj_t *value;
302135446Strhodes	int i;
303135446Strhodes
304135446Strhodes	for (i = 0;; i++) {
305135446Strhodes		if (maps[i] == NULL)
306135446Strhodes			return (ISC_R_NOTFOUND);
307135446Strhodes		checknames = NULL;
308254897Serwin		if (cfg_map_get(maps[i], "check-names",
309254897Serwin				&checknames) == ISC_R_SUCCESS) {
310135446Strhodes			/*
311135446Strhodes			 * Zone map entry is not a list.
312135446Strhodes			 */
313135446Strhodes			if (checknames != NULL && !cfg_obj_islist(checknames)) {
314135446Strhodes				*obj = checknames;
315135446Strhodes				return (ISC_R_SUCCESS);
316135446Strhodes			}
317135446Strhodes			for (element = cfg_list_first(checknames);
318135446Strhodes			     element != NULL;
319135446Strhodes			     element = cfg_list_next(element)) {
320135446Strhodes				value = cfg_listelt_value(element);
321135446Strhodes				type = cfg_tuple_get(value, "type");
322254897Serwin				if (strcasecmp(cfg_obj_asstring(type),
323254897Serwin					       which) == 0) {
324135446Strhodes					*obj = cfg_tuple_get(value, "mode");
325135446Strhodes					return (ISC_R_SUCCESS);
326135446Strhodes				}
327135446Strhodes			}
328135446Strhodes
329135446Strhodes		}
330135446Strhodes	}
331135446Strhodes}
332135446Strhodes
333135446Strhodesint
334165071Sdougbns_config_listcount(const cfg_obj_t *list) {
335165071Sdougb	const cfg_listelt_t *e;
336135446Strhodes	int i = 0;
337135446Strhodes
338135446Strhodes	for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e))
339135446Strhodes		i++;
340135446Strhodes
341135446Strhodes	return (i);
342135446Strhodes}
343135446Strhodes
344135446Strhodesisc_result_t
345165071Sdougbns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
346135446Strhodes		   dns_rdataclass_t *classp) {
347135446Strhodes	isc_textregion_t r;
348135446Strhodes	isc_result_t result;
349135446Strhodes
350135446Strhodes	if (!cfg_obj_isstring(classobj)) {
351135446Strhodes		*classp = defclass;
352135446Strhodes		return (ISC_R_SUCCESS);
353135446Strhodes	}
354170222Sdougb	DE_CONST(cfg_obj_asstring(classobj), r.base);
355170222Sdougb	r.length = strlen(r.base);
356135446Strhodes	result = dns_rdataclass_fromtext(classp, &r);
357135446Strhodes	if (result != ISC_R_SUCCESS)
358135446Strhodes		cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
359170222Sdougb			    "unknown class '%s'", r.base);
360135446Strhodes	return (result);
361135446Strhodes}
362135446Strhodes
363135446Strhodesisc_result_t
364165071Sdougbns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
365135446Strhodes		   dns_rdatatype_t *typep) {
366135446Strhodes	isc_textregion_t r;
367135446Strhodes	isc_result_t result;
368135446Strhodes
369135446Strhodes	if (!cfg_obj_isstring(typeobj)) {
370135446Strhodes		*typep = deftype;
371135446Strhodes		return (ISC_R_SUCCESS);
372135446Strhodes	}
373170222Sdougb	DE_CONST(cfg_obj_asstring(typeobj), r.base);
374170222Sdougb	r.length = strlen(r.base);
375135446Strhodes	result = dns_rdatatype_fromtext(typep, &r);
376135446Strhodes	if (result != ISC_R_SUCCESS)
377135446Strhodes		cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR,
378170222Sdougb			    "unknown type '%s'", r.base);
379135446Strhodes	return (result);
380135446Strhodes}
381135446Strhodes
382135446Strhodesdns_zonetype_t
383165071Sdougbns_config_getzonetype(const cfg_obj_t *zonetypeobj) {
384135446Strhodes	dns_zonetype_t ztype = dns_zone_none;
385165071Sdougb	const char *str;
386135446Strhodes
387135446Strhodes	str = cfg_obj_asstring(zonetypeobj);
388135446Strhodes	if (strcasecmp(str, "master") == 0)
389135446Strhodes		ztype = dns_zone_master;
390135446Strhodes	else if (strcasecmp(str, "slave") == 0)
391135446Strhodes		ztype = dns_zone_slave;
392135446Strhodes	else if (strcasecmp(str, "stub") == 0)
393135446Strhodes		ztype = dns_zone_stub;
394224092Sdougb	else if (strcasecmp(str, "static-stub") == 0)
395224092Sdougb		ztype = dns_zone_staticstub;
396254897Serwin	else if (strcasecmp(str, "redirect") == 0)
397254897Serwin		ztype = dns_zone_redirect;
398135446Strhodes	else
399135446Strhodes		INSIST(0);
400135446Strhodes	return (ztype);
401135446Strhodes}
402135446Strhodes
403135446Strhodesisc_result_t
404165071Sdougbns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
405135446Strhodes		    in_port_t defport, isc_mem_t *mctx,
406135446Strhodes		    isc_sockaddr_t **addrsp, isc_uint32_t *countp)
407135446Strhodes{
408135446Strhodes	int count, i = 0;
409165071Sdougb	const cfg_obj_t *addrlist;
410165071Sdougb	const cfg_obj_t *portobj;
411165071Sdougb	const cfg_listelt_t *element;
412135446Strhodes	isc_sockaddr_t *addrs;
413135446Strhodes	in_port_t port;
414135446Strhodes	isc_result_t result;
415135446Strhodes
416135446Strhodes	INSIST(addrsp != NULL && *addrsp == NULL);
417135446Strhodes	INSIST(countp != NULL);
418135446Strhodes
419135446Strhodes	addrlist = cfg_tuple_get(list, "addresses");
420135446Strhodes	count = ns_config_listcount(addrlist);
421135446Strhodes
422135446Strhodes	portobj = cfg_tuple_get(list, "port");
423135446Strhodes	if (cfg_obj_isuint32(portobj)) {
424135446Strhodes		isc_uint32_t val = cfg_obj_asuint32(portobj);
425135446Strhodes		if (val > ISC_UINT16_MAX) {
426135446Strhodes			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
427135446Strhodes				    "port '%u' out of range", val);
428135446Strhodes			return (ISC_R_RANGE);
429135446Strhodes		}
430135446Strhodes		port = (in_port_t) val;
431135446Strhodes	} else if (defport != 0)
432135446Strhodes		port = defport;
433135446Strhodes	else {
434135446Strhodes		result = ns_config_getport(config, &port);
435135446Strhodes		if (result != ISC_R_SUCCESS)
436135446Strhodes			return (result);
437135446Strhodes	}
438135446Strhodes
439135446Strhodes	addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
440135446Strhodes	if (addrs == NULL)
441135446Strhodes		return (ISC_R_NOMEMORY);
442135446Strhodes
443135446Strhodes	for (element = cfg_list_first(addrlist);
444135446Strhodes	     element != NULL;
445135446Strhodes	     element = cfg_list_next(element), i++)
446135446Strhodes	{
447135446Strhodes		INSIST(i < count);
448135446Strhodes		addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element));
449135446Strhodes		if (isc_sockaddr_getport(&addrs[i]) == 0)
450135446Strhodes			isc_sockaddr_setport(&addrs[i], port);
451135446Strhodes	}
452135446Strhodes	INSIST(i == count);
453135446Strhodes
454135446Strhodes	*addrsp = addrs;
455135446Strhodes	*countp = count;
456135446Strhodes
457135446Strhodes	return (ISC_R_SUCCESS);
458135446Strhodes}
459135446Strhodes
460135446Strhodesvoid
461135446Strhodesns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
462135446Strhodes		    isc_uint32_t count)
463135446Strhodes{
464135446Strhodes	INSIST(addrsp != NULL && *addrsp != NULL);
465135446Strhodes
466135446Strhodes	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
467135446Strhodes	*addrsp = NULL;
468135446Strhodes}
469135446Strhodes
470135446Strhodesstatic isc_result_t
471165071Sdougbget_masters_def(const cfg_obj_t *cctx, const char *name,
472186462Sdougb		const cfg_obj_t **ret)
473165071Sdougb{
474135446Strhodes	isc_result_t result;
475165071Sdougb	const cfg_obj_t *masters = NULL;
476165071Sdougb	const cfg_listelt_t *elt;
477135446Strhodes
478135446Strhodes	result = cfg_map_get(cctx, "masters", &masters);
479135446Strhodes	if (result != ISC_R_SUCCESS)
480135446Strhodes		return (result);
481135446Strhodes	for (elt = cfg_list_first(masters);
482135446Strhodes	     elt != NULL;
483135446Strhodes	     elt = cfg_list_next(elt)) {
484165071Sdougb		const cfg_obj_t *list;
485135446Strhodes		const char *listname;
486135446Strhodes
487135446Strhodes		list = cfg_listelt_value(elt);
488135446Strhodes		listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
489135446Strhodes
490135446Strhodes		if (strcasecmp(listname, name) == 0) {
491135446Strhodes			*ret = list;
492135446Strhodes			return (ISC_R_SUCCESS);
493135446Strhodes		}
494135446Strhodes	}
495135446Strhodes	return (ISC_R_NOTFOUND);
496135446Strhodes}
497135446Strhodes
498135446Strhodesisc_result_t
499165071Sdougbns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
500165071Sdougb			  isc_mem_t *mctx, isc_sockaddr_t **addrsp,
501165071Sdougb			  dns_name_t ***keysp, isc_uint32_t *countp)
502135446Strhodes{
503135446Strhodes	isc_uint32_t addrcount = 0, keycount = 0, i = 0;
504135446Strhodes	isc_uint32_t listcount = 0, l = 0, j;
505135446Strhodes	isc_uint32_t stackcount = 0, pushed = 0;
506135446Strhodes	isc_result_t result;
507165071Sdougb	const cfg_listelt_t *element;
508165071Sdougb	const cfg_obj_t *addrlist;
509165071Sdougb	const cfg_obj_t *portobj;
510135446Strhodes	in_port_t port;
511135446Strhodes	dns_fixedname_t fname;
512135446Strhodes	isc_sockaddr_t *addrs = NULL;
513135446Strhodes	dns_name_t **keys = NULL;
514170222Sdougb	struct { const char *name; } *lists = NULL;
515135446Strhodes	struct {
516165071Sdougb		const cfg_listelt_t *element;
517135446Strhodes		in_port_t port;
518135446Strhodes	} *stack = NULL;
519135446Strhodes
520135446Strhodes	REQUIRE(addrsp != NULL && *addrsp == NULL);
521135446Strhodes	REQUIRE(keysp != NULL && *keysp == NULL);
522135446Strhodes	REQUIRE(countp != NULL);
523135446Strhodes
524135446Strhodes newlist:
525135446Strhodes	addrlist = cfg_tuple_get(list, "addresses");
526135446Strhodes	portobj = cfg_tuple_get(list, "port");
527135446Strhodes	if (cfg_obj_isuint32(portobj)) {
528135446Strhodes		isc_uint32_t val = cfg_obj_asuint32(portobj);
529135446Strhodes		if (val > ISC_UINT16_MAX) {
530135446Strhodes			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
531135446Strhodes				    "port '%u' out of range", val);
532165071Sdougb			result = ISC_R_RANGE;
533165071Sdougb			goto cleanup;
534135446Strhodes		}
535135446Strhodes		port = (in_port_t) val;
536135446Strhodes	} else {
537135446Strhodes		result = ns_config_getport(config, &port);
538135446Strhodes		if (result != ISC_R_SUCCESS)
539165071Sdougb			goto cleanup;
540135446Strhodes	}
541135446Strhodes
542135446Strhodes	result = ISC_R_NOMEMORY;
543135446Strhodes
544135446Strhodes	element = cfg_list_first(addrlist);
545135446Strhodes resume:
546135446Strhodes	for ( ;
547135446Strhodes	     element != NULL;
548135446Strhodes	     element = cfg_list_next(element))
549135446Strhodes	{
550165071Sdougb		const cfg_obj_t *addr;
551165071Sdougb		const cfg_obj_t *key;
552165071Sdougb		const char *keystr;
553135446Strhodes		isc_buffer_t b;
554135446Strhodes
555135446Strhodes		addr = cfg_tuple_get(cfg_listelt_value(element),
556135446Strhodes				     "masterselement");
557135446Strhodes		key = cfg_tuple_get(cfg_listelt_value(element), "key");
558135446Strhodes
559135446Strhodes		if (!cfg_obj_issockaddr(addr)) {
560165071Sdougb			const char *listname = cfg_obj_asstring(addr);
561135446Strhodes			isc_result_t tresult;
562135446Strhodes
563135446Strhodes			/* Grow lists? */
564135446Strhodes			if (listcount == l) {
565135446Strhodes				void * new;
566135446Strhodes				isc_uint32_t newlen = listcount + 16;
567135446Strhodes				size_t newsize, oldsize;
568135446Strhodes
569135446Strhodes				newsize = newlen * sizeof(*lists);
570135446Strhodes				oldsize = listcount * sizeof(*lists);
571135446Strhodes				new = isc_mem_get(mctx, newsize);
572135446Strhodes				if (new == NULL)
573135446Strhodes					goto cleanup;
574135446Strhodes				if (listcount != 0) {
575262706Serwin					memmove(new, lists, oldsize);
576135446Strhodes					isc_mem_put(mctx, lists, oldsize);
577135446Strhodes				}
578135446Strhodes				lists = new;
579135446Strhodes				listcount = newlen;
580135446Strhodes			}
581135446Strhodes			/* Seen? */
582135446Strhodes			for (j = 0; j < l; j++)
583170222Sdougb				if (strcasecmp(lists[j].name, listname) == 0)
584135446Strhodes					break;
585135446Strhodes			if (j < l)
586135446Strhodes				continue;
587135446Strhodes			tresult = get_masters_def(config, listname, &list);
588135446Strhodes			if (tresult == ISC_R_NOTFOUND) {
589135446Strhodes				cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR,
590186462Sdougb				    "masters \"%s\" not found", listname);
591135446Strhodes
592135446Strhodes				result = tresult;
593135446Strhodes				goto cleanup;
594135446Strhodes			}
595135446Strhodes			if (tresult != ISC_R_SUCCESS)
596135446Strhodes				goto cleanup;
597170222Sdougb			lists[l++].name = listname;
598135446Strhodes			/* Grow stack? */
599135446Strhodes			if (stackcount == pushed) {
600135446Strhodes				void * new;
601135446Strhodes				isc_uint32_t newlen = stackcount + 16;
602135446Strhodes				size_t newsize, oldsize;
603135446Strhodes
604135446Strhodes				newsize = newlen * sizeof(*stack);
605135446Strhodes				oldsize = stackcount * sizeof(*stack);
606135446Strhodes				new = isc_mem_get(mctx, newsize);
607135446Strhodes				if (new == NULL)
608135446Strhodes					goto cleanup;
609135446Strhodes				if (stackcount != 0) {
610262706Serwin					memmove(new, stack, oldsize);
611135446Strhodes					isc_mem_put(mctx, stack, oldsize);
612135446Strhodes				}
613135446Strhodes				stack = new;
614135446Strhodes				stackcount = newlen;
615135446Strhodes			}
616135446Strhodes			/*
617135446Strhodes			 * We want to resume processing this list on the
618135446Strhodes			 * next element.
619135446Strhodes			 */
620135446Strhodes			stack[pushed].element = cfg_list_next(element);
621135446Strhodes			stack[pushed].port = port;
622135446Strhodes			pushed++;
623135446Strhodes			goto newlist;
624135446Strhodes		}
625135446Strhodes
626135446Strhodes		if (i == addrcount) {
627135446Strhodes			void * new;
628135446Strhodes			isc_uint32_t newlen = addrcount + 16;
629135446Strhodes			size_t newsize, oldsize;
630135446Strhodes
631135446Strhodes			newsize = newlen * sizeof(isc_sockaddr_t);
632135446Strhodes			oldsize = addrcount * sizeof(isc_sockaddr_t);
633135446Strhodes			new = isc_mem_get(mctx, newsize);
634135446Strhodes			if (new == NULL)
635135446Strhodes				goto cleanup;
636135446Strhodes			if (addrcount != 0) {
637262706Serwin				memmove(new, addrs, oldsize);
638135446Strhodes				isc_mem_put(mctx, addrs, oldsize);
639135446Strhodes			}
640135446Strhodes			addrs = new;
641135446Strhodes			addrcount = newlen;
642135446Strhodes
643135446Strhodes			newsize = newlen * sizeof(dns_name_t *);
644135446Strhodes			oldsize = keycount * sizeof(dns_name_t *);
645135446Strhodes			new = isc_mem_get(mctx, newsize);
646135446Strhodes			if (new == NULL)
647135446Strhodes				goto cleanup;
648135446Strhodes			if (keycount != 0) {
649262706Serwin				memmove(new, keys, oldsize);
650143731Sdougb				isc_mem_put(mctx, keys, oldsize);
651135446Strhodes			}
652135446Strhodes			keys = new;
653135446Strhodes			keycount = newlen;
654135446Strhodes		}
655135446Strhodes
656135446Strhodes		addrs[i] = *cfg_obj_assockaddr(addr);
657135446Strhodes		if (isc_sockaddr_getport(&addrs[i]) == 0)
658135446Strhodes			isc_sockaddr_setport(&addrs[i], port);
659135446Strhodes		keys[i] = NULL;
660254402Serwin		i++;	/* Increment here so that cleanup on error works. */
661254402Serwin		if (!cfg_obj_isstring(key))
662135446Strhodes			continue;
663254402Serwin		keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t));
664254402Serwin		if (keys[i - 1] == NULL)
665135446Strhodes			goto cleanup;
666254402Serwin		dns_name_init(keys[i - 1], NULL);
667186462Sdougb
668135446Strhodes		keystr = cfg_obj_asstring(key);
669254402Serwin		isc_buffer_constinit(&b, keystr, strlen(keystr));
670135446Strhodes		isc_buffer_add(&b, strlen(keystr));
671135446Strhodes		dns_fixedname_init(&fname);
672135446Strhodes		result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
673224092Sdougb					   dns_rootname, 0, NULL);
674135446Strhodes		if (result != ISC_R_SUCCESS)
675135446Strhodes			goto cleanup;
676135446Strhodes		result = dns_name_dup(dns_fixedname_name(&fname), mctx,
677254402Serwin				      keys[i - 1]);
678135446Strhodes		if (result != ISC_R_SUCCESS)
679135446Strhodes			goto cleanup;
680135446Strhodes	}
681135446Strhodes	if (pushed != 0) {
682135446Strhodes		pushed--;
683135446Strhodes		element = stack[pushed].element;
684135446Strhodes		port = stack[pushed].port;
685135446Strhodes		goto resume;
686135446Strhodes	}
687135446Strhodes	if (i < addrcount) {
688135446Strhodes		void * new;
689135446Strhodes		size_t newsize, oldsize;
690135446Strhodes
691135446Strhodes		newsize = i * sizeof(isc_sockaddr_t);
692135446Strhodes		oldsize = addrcount * sizeof(isc_sockaddr_t);
693135446Strhodes		if (i != 0) {
694135446Strhodes			new = isc_mem_get(mctx, newsize);
695135446Strhodes			if (new == NULL)
696135446Strhodes				goto cleanup;
697262706Serwin			memmove(new, addrs, newsize);
698135446Strhodes		} else
699135446Strhodes			new = NULL;
700165071Sdougb		isc_mem_put(mctx, addrs, oldsize);
701135446Strhodes		addrs = new;
702135446Strhodes		addrcount = i;
703135446Strhodes
704135446Strhodes		newsize = i * sizeof(dns_name_t *);
705135446Strhodes		oldsize = keycount * sizeof(dns_name_t *);
706135446Strhodes		if (i != 0) {
707135446Strhodes			new = isc_mem_get(mctx, newsize);
708135446Strhodes			if (new == NULL)
709135446Strhodes				goto cleanup;
710262706Serwin			memmove(new, keys,  newsize);
711135446Strhodes		} else
712135446Strhodes			new = NULL;
713165071Sdougb		isc_mem_put(mctx, keys, oldsize);
714135446Strhodes		keys = new;
715135446Strhodes		keycount = i;
716135446Strhodes	}
717135446Strhodes
718135446Strhodes	if (lists != NULL)
719135446Strhodes		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
720135446Strhodes	if (stack != NULL)
721135446Strhodes		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
722186462Sdougb
723135446Strhodes	INSIST(keycount == addrcount);
724135446Strhodes
725135446Strhodes	*addrsp = addrs;
726135446Strhodes	*keysp = keys;
727135446Strhodes	*countp = addrcount;
728135446Strhodes
729135446Strhodes	return (ISC_R_SUCCESS);
730135446Strhodes
731135446Strhodes cleanup:
732135446Strhodes	if (addrs != NULL)
733135446Strhodes		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
734135446Strhodes	if (keys != NULL) {
735254402Serwin		for (j = 0; j < i; j++) {
736135446Strhodes			if (keys[j] == NULL)
737135446Strhodes				continue;
738135446Strhodes			if (dns_name_dynamic(keys[j]))
739135446Strhodes				dns_name_free(keys[j], mctx);
740135446Strhodes			isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
741135446Strhodes		}
742135446Strhodes		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
743135446Strhodes	}
744135446Strhodes	if (lists != NULL)
745135446Strhodes		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
746135446Strhodes	if (stack != NULL)
747135446Strhodes		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
748135446Strhodes	return (result);
749135446Strhodes}
750135446Strhodes
751135446Strhodesvoid
752135446Strhodesns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
753135446Strhodes			  dns_name_t ***keysp, isc_uint32_t count)
754135446Strhodes{
755135446Strhodes	unsigned int i;
756135446Strhodes	dns_name_t **keys = *keysp;
757135446Strhodes
758135446Strhodes	INSIST(addrsp != NULL && *addrsp != NULL);
759135446Strhodes
760135446Strhodes	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
761135446Strhodes	for (i = 0; i < count; i++) {
762135446Strhodes		if (keys[i] == NULL)
763135446Strhodes			continue;
764135446Strhodes		if (dns_name_dynamic(keys[i]))
765135446Strhodes			dns_name_free(keys[i], mctx);
766135446Strhodes		isc_mem_put(mctx, keys[i], sizeof(dns_name_t));
767135446Strhodes	}
768135446Strhodes	isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *));
769135446Strhodes	*addrsp = NULL;
770135446Strhodes	*keysp = NULL;
771135446Strhodes}
772135446Strhodes
773135446Strhodesisc_result_t
774165071Sdougbns_config_getport(const cfg_obj_t *config, in_port_t *portp) {
775165071Sdougb	const cfg_obj_t *maps[3];
776165071Sdougb	const cfg_obj_t *options = NULL;
777165071Sdougb	const cfg_obj_t *portobj = NULL;
778135446Strhodes	isc_result_t result;
779135446Strhodes	int i;
780135446Strhodes
781135446Strhodes	(void)cfg_map_get(config, "options", &options);
782135446Strhodes	i = 0;
783135446Strhodes	if (options != NULL)
784135446Strhodes		maps[i++] = options;
785135446Strhodes	maps[i++] = ns_g_defaults;
786135446Strhodes	maps[i] = NULL;
787135446Strhodes
788135446Strhodes	result = ns_config_get(maps, "port", &portobj);
789135446Strhodes	INSIST(result == ISC_R_SUCCESS);
790135446Strhodes	if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
791135446Strhodes		cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
792135446Strhodes			    "port '%u' out of range",
793135446Strhodes			    cfg_obj_asuint32(portobj));
794135446Strhodes		return (ISC_R_RANGE);
795135446Strhodes	}
796135446Strhodes	*portp = (in_port_t)cfg_obj_asuint32(portobj);
797135446Strhodes	return (ISC_R_SUCCESS);
798135446Strhodes}
799135446Strhodes
800170222Sdougbstruct keyalgorithms {
801170222Sdougb	const char *str;
802170222Sdougb	enum { hmacnone, hmacmd5, hmacsha1, hmacsha224,
803170222Sdougb	       hmacsha256, hmacsha384, hmacsha512 } hmac;
804224092Sdougb	unsigned int type;
805170222Sdougb	isc_uint16_t size;
806170222Sdougb} algorithms[] = {
807224092Sdougb	{ "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 },
808224092Sdougb	{ "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 },
809224092Sdougb	{ "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 },
810224092Sdougb	{ "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 },
811224092Sdougb	{ "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 },
812224092Sdougb	{ "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 },
813224092Sdougb	{ "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 },
814224092Sdougb	{ "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 },
815224092Sdougb	{  NULL, hmacnone, DST_ALG_UNKNOWN, 0 }
816170222Sdougb};
817170222Sdougb
818135446Strhodesisc_result_t
819170222Sdougbns_config_getkeyalgorithm(const char *str, dns_name_t **name,
820170222Sdougb			  isc_uint16_t *digestbits)
821135446Strhodes{
822224092Sdougb	return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits));
823224092Sdougb}
824224092Sdougb
825224092Sdougbisc_result_t
826224092Sdougbns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
827224092Sdougb			   unsigned int *typep, isc_uint16_t *digestbits)
828224092Sdougb{
829170222Sdougb	int i;
830170222Sdougb	size_t len = 0;
831170222Sdougb	isc_uint16_t bits;
832170222Sdougb	isc_result_t result;
833170222Sdougb
834170222Sdougb	for (i = 0; algorithms[i].str != NULL; i++) {
835170222Sdougb		len = strlen(algorithms[i].str);
836170222Sdougb		if (strncasecmp(algorithms[i].str, str, len) == 0 &&
837170222Sdougb		    (str[len] == '\0' ||
838170222Sdougb		     (algorithms[i].size != 0 && str[len] == '-')))
839170222Sdougb			break;
840135446Strhodes	}
841170222Sdougb	if (algorithms[i].str == NULL)
842170222Sdougb		return (ISC_R_NOTFOUND);
843170222Sdougb	if (str[len] == '-') {
844170222Sdougb		result = isc_parse_uint16(&bits, str + len + 1, 10);
845170222Sdougb		if (result != ISC_R_SUCCESS)
846170222Sdougb			return (result);
847170222Sdougb		if (bits > algorithms[i].size)
848170222Sdougb			return (ISC_R_RANGE);
849170222Sdougb	} else if (algorithms[i].size == 0)
850170222Sdougb		bits = 128;
851170222Sdougb	else
852170222Sdougb		bits = algorithms[i].size;
853170222Sdougb
854170222Sdougb	if (name != NULL) {
855170222Sdougb		switch (algorithms[i].hmac) {
856170222Sdougb		case hmacmd5: *name = dns_tsig_hmacmd5_name; break;
857170222Sdougb		case hmacsha1: *name = dns_tsig_hmacsha1_name; break;
858170222Sdougb		case hmacsha224: *name = dns_tsig_hmacsha224_name; break;
859170222Sdougb		case hmacsha256: *name = dns_tsig_hmacsha256_name; break;
860170222Sdougb		case hmacsha384: *name = dns_tsig_hmacsha384_name; break;
861170222Sdougb		case hmacsha512: *name = dns_tsig_hmacsha512_name; break;
862170222Sdougb		default:
863170222Sdougb			INSIST(0);
864170222Sdougb		}
865170222Sdougb	}
866224092Sdougb	if (typep != NULL)
867224092Sdougb		*typep = algorithms[i].type;
868170222Sdougb	if (digestbits != NULL)
869170222Sdougb		*digestbits = bits;
870170222Sdougb	return (ISC_R_SUCCESS);
871135446Strhodes}
872