xref: /netbsd-src/external/mpl/bind/dist/bin/named/config.c (revision ae87de8892f277bece3527c15b186ebcfa188227)
1 /*	$NetBSD: config.c,v 1.14 2023/01/25 21:43:23 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <bind.keys.h>
19 #include <inttypes.h>
20 #include <stdlib.h>
21 
22 #include <isc/buffer.h>
23 #include <isc/log.h>
24 #include <isc/mem.h>
25 #include <isc/netmgr.h>
26 #include <isc/parseint.h>
27 #include <isc/region.h>
28 #include <isc/result.h>
29 #include <isc/sockaddr.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32 
33 #include <pk11/site.h>
34 
35 #include <dns/fixedname.h>
36 #include <dns/name.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdatatype.h>
39 #include <dns/tsig.h>
40 #include <dns/zone.h>
41 
42 #include <dst/dst.h>
43 
44 #include <isccfg/grammar.h>
45 #include <isccfg/namedconf.h>
46 
47 #include <named/config.h>
48 #include <named/globals.h>
49 
50 /*% default configuration */
51 static char defaultconf[] = "\
52 options {\n\
53 	answer-cookie true;\n\
54 	automatic-interface-scan yes;\n\
55 	bindkeys-file \"" NAMED_SYSCONFDIR "/bind.keys\";\n\
56 #	blackhole {none;};\n\
57 	cookie-algorithm siphash24;\n"
58 #ifndef WIN32
59 			    "	coresize default;\n\
60 	datasize default;\n"
61 #endif /* ifndef WIN32 */
62 			    "\
63 #	directory <none>\n\
64 	dnssec-policy \"none\";\n\
65 	dump-file \"named_dump.db\";\n\
66 	edns-udp-size 1232;\n"
67 #ifndef WIN32
68 			    "	files unlimited;\n"
69 #endif /* ifndef WIN32 */
70 #if defined(HAVE_GEOIP2) && !defined(WIN32)
71 			    "	geoip-directory \"" MAXMINDDB_PREFIX
72 			    "/share/GeoIP\";\n"
73 #elif defined(HAVE_GEOIP2)
74 			    "	geoip-directory \".\";\n"
75 #endif /* if defined(HAVE_GEOIP2) && !defined(WIN32) */
76 			    "\
77 	heartbeat-interval 60;\n\
78 	interface-interval 60;\n\
79 #	keep-response-order {none;};\n\
80 	listen-on {any;};\n\
81 	listen-on-v6 {any;};\n\
82 #	lock-file \"" NAMED_LOCALSTATEDIR "/run/named/named.lock\";\n\
83 	match-mapped-addresses no;\n\
84 	max-ixfr-ratio unlimited;\n\
85 	max-rsa-exponent-size 0; /* no limit */\n\
86 	max-udp-size 1232;\n\
87 	memstatistics-file \"named.memstats\";\n\
88 	nocookie-udp-size 4096;\n\
89 	notify-rate 20;\n\
90 	nta-lifetime 3600;\n\
91 	nta-recheck 300;\n\
92 #	pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\
93 	port 53;\n"
94 #if HAVE_SO_REUSEPORT_LB
95 			    "\
96 	reuseport yes;\n"
97 #else
98 			    "\
99 	reuseport no;\n"
100 #endif
101 			    "\
102 	prefetch 2 9;\n\
103 	recursing-file \"named.recursing\";\n\
104 	recursive-clients 1000;\n\
105 	request-nsid false;\n\
106 	reserved-sockets 512;\n\
107 	resolver-query-timeout 10;\n\
108 	rrset-order { order random; };\n\
109 	secroots-file \"named.secroots\";\n\
110 	send-cookie true;\n\
111 	serial-query-rate 20;\n\
112 	server-id none;\n\
113 	session-keyalg hmac-sha256;\n\
114 #	session-keyfile \"" NAMED_LOCALSTATEDIR "/run/named/session.key\";\n\
115 	session-keyname local-ddns;\n"
116 #ifndef WIN32
117 			    "	stacksize default;\n"
118 #endif /* ifndef WIN32 */
119 			    "	startup-notify-rate 20;\n\
120 	statistics-file \"named.stats\";\n\
121 	tcp-advertised-timeout 300;\n\
122 	tcp-clients 150;\n\
123 	tcp-idle-timeout 300;\n\
124 	tcp-initial-timeout 300;\n\
125 	tcp-keepalive-timeout 300;\n\
126 	tcp-listen-queue 10;\n\
127 #	tkey-dhkey <none>\n\
128 #	tkey-domain <none>\n\
129 #	tkey-gssapi-credential <none>\n\
130 	transfer-message-size 20480;\n\
131 	transfers-in 10;\n\
132 	transfers-out 10;\n\
133 	transfers-per-ns 2;\n\
134 	trust-anchor-telemetry yes;\n\
135 	update-quota 100;\n\
136 \n\
137 	/* view */\n\
138 	allow-new-zones no;\n\
139 	allow-notify {none;};\n\
140 	allow-query-cache { localnets; localhost; };\n\
141 	allow-query-cache-on { any; };\n\
142 	allow-recursion { localnets; localhost; };\n\
143 	allow-recursion-on { any; };\n\
144 	allow-update-forwarding {none;};\n\
145 	auth-nxdomain false;\n\
146 	check-dup-records warn;\n\
147 	check-mx warn;\n\
148 	check-names primary fail;\n\
149 	check-names response ignore;\n\
150 	check-names secondary warn;\n\
151 	check-spf warn;\n\
152 	clients-per-query 10;\n\
153 	dnssec-accept-expired no;\n\
154 	dnssec-validation " VALIDATION_DEFAULT "; \n"
155 #ifdef HAVE_DNSTAP
156 			    "	dnstap-identity hostname;\n"
157 #endif /* ifdef HAVE_DNSTAP */
158 			    "\
159 	fetch-quota-params 100 0.1 0.3 0.7;\n\
160 	fetches-per-server 0;\n\
161 	fetches-per-zone 0;\n\
162 	glue-cache yes;\n\
163 	lame-ttl 0;\n"
164 #ifdef HAVE_LMDB
165 			    "	lmdb-mapsize 32M;\n"
166 #endif /* ifdef HAVE_LMDB */
167 			    "	max-cache-size 90%;\n\
168 	max-cache-ttl 604800; /* 1 week */\n\
169 	max-clients-per-query 100;\n\
170 	max-ncache-ttl 10800; /* 3 hours */\n\
171 	max-recursion-depth 7;\n\
172 	max-recursion-queries 100;\n\
173 	max-stale-ttl 86400; /* 1 day */\n\
174 	message-compression yes;\n\
175 	min-ncache-ttl 0; /* 0 hours */\n\
176 	min-cache-ttl 0; /* 0 seconds */\n\
177 	minimal-any false;\n\
178 	minimal-responses no-auth-recursive;\n\
179 	notify-source *;\n\
180 	notify-source-v6 *;\n\
181 	nsec3-test-zone no;\n\
182 	parental-source *;\n\
183 	parental-source-v6 *;\n\
184 	provide-ixfr true;\n\
185 	qname-minimization relaxed;\n\
186 	query-source address *;\n\
187 	query-source-v6 address *;\n\
188 	recursion true;\n\
189 	request-expire true;\n\
190 	request-ixfr true;\n\
191 	require-server-cookie no;\n\
192 	resolver-nonbackoff-tries 3;\n\
193 	resolver-retry-interval 800; /* in milliseconds */\n\
194 	root-key-sentinel yes;\n\
195 	servfail-ttl 1;\n\
196 #	sortlist <none>\n\
197 	stale-answer-client-timeout off;\n\
198 	stale-answer-enable false;\n\
199 	stale-answer-ttl 30; /* 30 seconds */\n\
200 	stale-cache-enable true;\n\
201 	stale-refresh-time 30; /* 30 seconds */\n\
202 	synth-from-dnssec no;\n\
203 #	topology <none>\n\
204 	transfer-format many-answers;\n\
205 	v6-bias 50;\n\
206 	zero-no-soa-ttl-cache no;\n\
207 \n\
208 	/* zone */\n\
209 	allow-query {any;};\n\
210 	allow-query-on {any;};\n\
211 	allow-transfer {any;};\n\
212 #	also-notify <none>\n\
213 	alt-transfer-source *;\n\
214 	alt-transfer-source-v6 *;\n\
215 	check-integrity yes;\n\
216 	check-mx-cname warn;\n\
217 	check-sibling yes;\n\
218 	check-srv-cname warn;\n\
219 	check-wildcard yes;\n\
220 	dialup no;\n\
221 	dnssec-dnskey-kskonly no;\n\
222 	dnssec-loadkeys-interval 60;\n\
223 	dnssec-secure-to-insecure no;\n\
224 	dnssec-update-mode maintain;\n\
225 #	forward <none>\n\
226 #	forwarders <none>\n\
227 #	inline-signing no;\n\
228 	ixfr-from-differences false;\n\
229 	max-journal-size default;\n\
230 	max-records 0;\n\
231 	max-refresh-time 2419200; /* 4 weeks */\n\
232 	max-retry-time 1209600; /* 2 weeks */\n\
233 	max-transfer-idle-in 60;\n\
234 	max-transfer-idle-out 60;\n\
235 	max-transfer-time-in 120;\n\
236 	max-transfer-time-out 120;\n\
237 	min-refresh-time 300;\n\
238 	min-retry-time 500;\n\
239 	multi-master no;\n\
240 	notify yes;\n\
241 	notify-delay 5;\n\
242 	notify-to-soa no;\n\
243 	serial-update-method increment;\n\
244 	sig-signing-nodes 100;\n\
245 	sig-signing-signatures 10;\n\
246 	sig-signing-type 65534;\n\
247 	sig-validity-interval 30; /* days */\n\
248 	dnskey-sig-validity 0; /* default: sig-validity-interval */\n\
249 	transfer-source *;\n\
250 	transfer-source-v6 *;\n\
251 	try-tcp-refresh yes; /* BIND 8 compat */\n\
252 	update-check-ksk yes;\n\
253 	zero-no-soa-ttl yes;\n\
254 	zone-statistics terse;\n\
255 };\n\
256 "
257 
258 			    "#\n\
259 #  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
260 #\n\
261 view \"_bind\" chaos {\n\
262 	recursion no;\n\
263 	notify no;\n\
264 	allow-new-zones no;\n\
265 	max-cache-size 2M;\n\
266 \n\
267 	# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
268 	rate-limit {\n\
269 		responses-per-second 3;\n\
270 		slip 0;\n\
271 		min-table-size 10;\n\
272 	};\n\
273 \n\
274 	zone \"version.bind\" chaos {\n\
275 		type primary;\n\
276 		database \"_builtin version\";\n\
277 	};\n\
278 \n\
279 	zone \"hostname.bind\" chaos {\n\
280 		type primary;\n\
281 		database \"_builtin hostname\";\n\
282 	};\n\
283 \n\
284 	zone \"authors.bind\" chaos {\n\
285 		type primary;\n\
286 		database \"_builtin authors\";\n\
287 	};\n\
288 \n\
289 	zone \"id.server\" chaos {\n\
290 		type primary;\n\
291 		database \"_builtin id\";\n\
292 	};\n\
293 };\n\
294 "
295 			    "#\n\
296 #  Default trusted key(s), used if \n\
297 # \"dnssec-validation auto;\" is set and\n\
298 #  " NAMED_SYSCONFDIR "/bind.keys doesn't exist).\n\
299 #\n\
300 # BEGIN TRUST ANCHORS\n"
301 
302 	/* Imported from bind.keys.h: */
303 	TRUST_ANCHORS
304 
305 			    "# END TRUST ANCHORS\n\
306 \n\
307 primaries " DEFAULT_IANA_ROOT_ZONE_PRIMARIES " {\n\
308 	2001:500:200::b;	# b.root-servers.net\n\
309 	2001:500:2::c;		# c.root-servers.net\n\
310 	2001:500:2f::f;		# f.root-servers.net\n\
311 	2001:500:12::d0d;	# g.root-servers.net\n\
312 	2001:7fd::1;		# k.root-servers.net\n\
313 	2620:0:2830:202::132;	# xfr.cjr.dns.icann.org\n\
314 	2620:0:2d0:202::132;	# xfr.lax.dns.icann.org\n\
315 	199.9.14.201;		# b.root-servers.net\n\
316 	192.33.4.12;		# c.root-servers.net\n\
317 	192.5.5.241;		# f.root-servers.net\n\
318 	192.112.36.4;		# g.root-servers.net\n\
319 	193.0.14.129;		# k.root-servers.net\n\
320 	192.0.47.132;		# xfr.cjr.dns.icann.org\n\
321 	192.0.32.132;		# xfr.lax.dns.icann.org\n\
322 };\n\
323 ";
324 
325 isc_result_t
326 named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
327 	isc_buffer_t b;
328 
329 	isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1);
330 	isc_buffer_add(&b, sizeof(defaultconf) - 1);
331 	return (cfg_parse_buffer(parser, &b, __FILE__, 0, &cfg_type_namedconf,
332 				 CFG_PCTX_NODEPRECATED, conf));
333 }
334 
335 const char *
336 named_config_getdefault(void) {
337 	return (defaultconf);
338 }
339 
340 isc_result_t
341 named_config_get(cfg_obj_t const *const *maps, const char *name,
342 		 const cfg_obj_t **obj) {
343 	int i;
344 
345 	for (i = 0; maps[i] != NULL; i++) {
346 		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
347 			return (ISC_R_SUCCESS);
348 		}
349 	}
350 	return (ISC_R_NOTFOUND);
351 }
352 
353 isc_result_t
354 named_checknames_get(const cfg_obj_t **maps, const char *const names[],
355 		     const cfg_obj_t **obj) {
356 	const cfg_listelt_t *element;
357 	const cfg_obj_t *checknames;
358 	const cfg_obj_t *type;
359 	const cfg_obj_t *value;
360 	int i;
361 
362 	REQUIRE(maps != NULL);
363 	REQUIRE(names != NULL);
364 	REQUIRE(obj != NULL && *obj == NULL);
365 
366 	for (i = 0; maps[i] != NULL; i++) {
367 		checknames = NULL;
368 		if (cfg_map_get(maps[i], "check-names", &checknames) ==
369 		    ISC_R_SUCCESS)
370 		{
371 			/*
372 			 * Zone map entry is not a list.
373 			 */
374 			if (checknames != NULL && !cfg_obj_islist(checknames)) {
375 				*obj = checknames;
376 				return (ISC_R_SUCCESS);
377 			}
378 			for (element = cfg_list_first(checknames);
379 			     element != NULL; element = cfg_list_next(element))
380 			{
381 				value = cfg_listelt_value(element);
382 				type = cfg_tuple_get(value, "type");
383 
384 				for (size_t j = 0; names[j] != NULL; j++) {
385 					if (strcasecmp(cfg_obj_asstring(type),
386 						       names[j]) == 0)
387 					{
388 						*obj = cfg_tuple_get(value,
389 								     "mode");
390 						return (ISC_R_SUCCESS);
391 					}
392 				}
393 			}
394 		}
395 	}
396 	return (ISC_R_NOTFOUND);
397 }
398 
399 int
400 named_config_listcount(const cfg_obj_t *list) {
401 	const cfg_listelt_t *e;
402 	int i = 0;
403 
404 	for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e)) {
405 		i++;
406 	}
407 
408 	return (i);
409 }
410 
411 isc_result_t
412 named_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
413 		      dns_rdataclass_t *classp) {
414 	isc_textregion_t r;
415 	isc_result_t result;
416 
417 	if (!cfg_obj_isstring(classobj)) {
418 		*classp = defclass;
419 		return (ISC_R_SUCCESS);
420 	}
421 	DE_CONST(cfg_obj_asstring(classobj), r.base);
422 	r.length = strlen(r.base);
423 	result = dns_rdataclass_fromtext(classp, &r);
424 	if (result != ISC_R_SUCCESS) {
425 		cfg_obj_log(classobj, named_g_lctx, ISC_LOG_ERROR,
426 			    "unknown class '%s'", r.base);
427 	}
428 	return (result);
429 }
430 
431 isc_result_t
432 named_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
433 		     dns_rdatatype_t *typep) {
434 	isc_textregion_t r;
435 	isc_result_t result;
436 
437 	if (!cfg_obj_isstring(typeobj)) {
438 		*typep = deftype;
439 		return (ISC_R_SUCCESS);
440 	}
441 	DE_CONST(cfg_obj_asstring(typeobj), r.base);
442 	r.length = strlen(r.base);
443 	result = dns_rdatatype_fromtext(typep, &r);
444 	if (result != ISC_R_SUCCESS) {
445 		cfg_obj_log(typeobj, named_g_lctx, ISC_LOG_ERROR,
446 			    "unknown type '%s'", r.base);
447 	}
448 	return (result);
449 }
450 
451 dns_zonetype_t
452 named_config_getzonetype(const cfg_obj_t *zonetypeobj) {
453 	dns_zonetype_t ztype = dns_zone_none;
454 	const char *str;
455 
456 	str = cfg_obj_asstring(zonetypeobj);
457 	if (strcasecmp(str, "primary") == 0 || strcasecmp(str, "master") == 0) {
458 		ztype = dns_zone_primary;
459 	} else if (strcasecmp(str, "secondary") == 0 ||
460 		   strcasecmp(str, "slave") == 0)
461 	{
462 		ztype = dns_zone_secondary;
463 	} else if (strcasecmp(str, "mirror") == 0) {
464 		ztype = dns_zone_mirror;
465 	} else if (strcasecmp(str, "stub") == 0) {
466 		ztype = dns_zone_stub;
467 	} else if (strcasecmp(str, "static-stub") == 0) {
468 		ztype = dns_zone_staticstub;
469 	} else if (strcasecmp(str, "redirect") == 0) {
470 		ztype = dns_zone_redirect;
471 	} else {
472 		UNREACHABLE();
473 	}
474 	return (ztype);
475 }
476 
477 isc_result_t
478 named_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
479 		       in_port_t defport, isc_mem_t *mctx,
480 		       isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp,
481 		       uint32_t *countp) {
482 	int count, i = 0;
483 	const cfg_obj_t *addrlist;
484 	const cfg_obj_t *portobj, *dscpobj;
485 	const cfg_listelt_t *element;
486 	isc_sockaddr_t *addrs;
487 	in_port_t port;
488 	isc_dscp_t dscp = -1, *dscps = NULL;
489 	isc_result_t result;
490 
491 	INSIST(addrsp != NULL && *addrsp == NULL);
492 	INSIST(dscpsp == NULL || *dscpsp == NULL);
493 	INSIST(countp != NULL);
494 
495 	addrlist = cfg_tuple_get(list, "addresses");
496 	count = named_config_listcount(addrlist);
497 
498 	portobj = cfg_tuple_get(list, "port");
499 	if (cfg_obj_isuint32(portobj)) {
500 		uint32_t val = cfg_obj_asuint32(portobj);
501 		if (val > UINT16_MAX) {
502 			cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
503 				    "port '%u' out of range", val);
504 			return (ISC_R_RANGE);
505 		}
506 		port = (in_port_t)val;
507 	} else if (defport != 0) {
508 		port = defport;
509 	} else {
510 		result = named_config_getport(config, &port);
511 		if (result != ISC_R_SUCCESS) {
512 			return (result);
513 		}
514 	}
515 
516 	if (dscpsp != NULL) {
517 		dscpobj = cfg_tuple_get(list, "dscp");
518 		if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) {
519 			if (cfg_obj_asuint32(dscpobj) > 63) {
520 				cfg_obj_log(dscpobj, named_g_lctx,
521 					    ISC_LOG_ERROR,
522 					    "dscp value '%u' is out of range",
523 					    cfg_obj_asuint32(dscpobj));
524 				return (ISC_R_RANGE);
525 			}
526 			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
527 		}
528 
529 		dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t));
530 	}
531 
532 	addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
533 
534 	for (element = cfg_list_first(addrlist); element != NULL;
535 	     element = cfg_list_next(element), i++)
536 	{
537 		const cfg_obj_t *addr;
538 		INSIST(i < count);
539 		addr = cfg_listelt_value(element);
540 		addrs[i] = *cfg_obj_assockaddr(addr);
541 		if (dscpsp != NULL) {
542 			isc_dscp_t innerdscp;
543 			innerdscp = cfg_obj_getdscp(addr);
544 			if (innerdscp == -1) {
545 				innerdscp = dscp;
546 			}
547 			dscps[i] = innerdscp;
548 		}
549 		if (isc_sockaddr_getport(&addrs[i]) == 0) {
550 			isc_sockaddr_setport(&addrs[i], port);
551 		}
552 	}
553 	INSIST(i == count);
554 
555 	*addrsp = addrs;
556 	*countp = count;
557 
558 	if (dscpsp != NULL) {
559 		*dscpsp = dscps;
560 	}
561 
562 	return (ISC_R_SUCCESS);
563 }
564 
565 void
566 named_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
567 		       isc_dscp_t **dscpsp, uint32_t count) {
568 	INSIST(addrsp != NULL && *addrsp != NULL);
569 	INSIST(dscpsp == NULL || *dscpsp != NULL);
570 
571 	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
572 	*addrsp = NULL;
573 
574 	if (dscpsp != NULL) {
575 		isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t));
576 		*dscpsp = NULL;
577 	}
578 }
579 
580 static isc_result_t
581 getremotesdef(const cfg_obj_t *cctx, const char *list, const char *name,
582 	      const cfg_obj_t **ret) {
583 	isc_result_t result;
584 	const cfg_obj_t *obj = NULL;
585 	const cfg_listelt_t *elt;
586 
587 	REQUIRE(cctx != NULL);
588 	REQUIRE(name != NULL);
589 	REQUIRE(ret != NULL && *ret == NULL);
590 
591 	result = cfg_map_get(cctx, list, &obj);
592 	if (result != ISC_R_SUCCESS) {
593 		return (result);
594 	}
595 	elt = cfg_list_first(obj);
596 	while (elt != NULL) {
597 		obj = cfg_listelt_value(elt);
598 		if (strcasecmp(cfg_obj_asstring(cfg_tuple_get(obj, "name")),
599 			       name) == 0)
600 		{
601 			*ret = obj;
602 			return (ISC_R_SUCCESS);
603 		}
604 		elt = cfg_list_next(elt);
605 	}
606 	return (ISC_R_NOTFOUND);
607 }
608 
609 isc_result_t
610 named_config_getremotesdef(const cfg_obj_t *cctx, const char *list,
611 			   const char *name, const cfg_obj_t **ret) {
612 	isc_result_t result;
613 
614 	if (strcmp(list, "parental-agents") == 0) {
615 		return (getremotesdef(cctx, list, name, ret));
616 	} else if (strcmp(list, "primaries") == 0) {
617 		result = getremotesdef(cctx, list, name, ret);
618 		if (result != ISC_R_SUCCESS) {
619 			result = getremotesdef(cctx, "masters", name, ret);
620 		}
621 		return (result);
622 	}
623 	return (ISC_R_NOTFOUND);
624 }
625 
626 isc_result_t
627 named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype,
628 			     const cfg_obj_t *list, isc_mem_t *mctx,
629 			     dns_ipkeylist_t *ipkl) {
630 	uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0;
631 	uint32_t listcount = 0, l = 0, j;
632 	uint32_t stackcount = 0, pushed = 0;
633 	isc_result_t result;
634 	const cfg_listelt_t *element;
635 	const cfg_obj_t *addrlist;
636 	const cfg_obj_t *portobj;
637 	const cfg_obj_t *dscpobj;
638 	in_port_t port;
639 	isc_dscp_t dscp = -1;
640 	dns_fixedname_t fname;
641 	isc_sockaddr_t *addrs = NULL;
642 	isc_dscp_t *dscps = NULL;
643 	dns_name_t **keys = NULL;
644 	struct {
645 		const char *name;
646 	} *lists = NULL;
647 	struct {
648 		const cfg_listelt_t *element;
649 		in_port_t port;
650 		isc_dscp_t dscp;
651 	} *stack = NULL;
652 
653 	REQUIRE(ipkl != NULL);
654 	REQUIRE(ipkl->count == 0);
655 	REQUIRE(ipkl->addrs == NULL);
656 	REQUIRE(ipkl->keys == NULL);
657 	REQUIRE(ipkl->dscps == NULL);
658 	REQUIRE(ipkl->labels == NULL);
659 	REQUIRE(ipkl->allocated == 0);
660 
661 	/*
662 	 * Get system defaults.
663 	 */
664 	result = named_config_getport(config, &port);
665 	if (result != ISC_R_SUCCESS) {
666 		goto cleanup;
667 	}
668 
669 	result = named_config_getdscp(config, &dscp);
670 	if (result != ISC_R_SUCCESS) {
671 		goto cleanup;
672 	}
673 
674 newlist:
675 	addrlist = cfg_tuple_get(list, "addresses");
676 	portobj = cfg_tuple_get(list, "port");
677 	dscpobj = cfg_tuple_get(list, "dscp");
678 
679 	if (cfg_obj_isuint32(portobj)) {
680 		uint32_t val = cfg_obj_asuint32(portobj);
681 		if (val > UINT16_MAX) {
682 			cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
683 				    "port '%u' out of range", val);
684 			result = ISC_R_RANGE;
685 			goto cleanup;
686 		}
687 		port = (in_port_t)val;
688 	}
689 
690 	if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) {
691 		if (cfg_obj_asuint32(dscpobj) > 63) {
692 			cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
693 				    "dscp value '%u' is out of range",
694 				    cfg_obj_asuint32(dscpobj));
695 			result = ISC_R_RANGE;
696 			goto cleanup;
697 		}
698 		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
699 	}
700 
701 	result = ISC_R_NOMEMORY;
702 
703 	element = cfg_list_first(addrlist);
704 resume:
705 	for (; element != NULL; element = cfg_list_next(element)) {
706 		const cfg_obj_t *addr;
707 		const cfg_obj_t *key;
708 		const char *keystr;
709 		isc_buffer_t b;
710 
711 		addr = cfg_tuple_get(cfg_listelt_value(element),
712 				     "remoteselement");
713 		key = cfg_tuple_get(cfg_listelt_value(element), "key");
714 
715 		if (!cfg_obj_issockaddr(addr)) {
716 			const char *listname = cfg_obj_asstring(addr);
717 			isc_result_t tresult;
718 
719 			/* Grow lists? */
720 			if (listcount == l) {
721 				void *tmp;
722 				uint32_t newlen = listcount + 16;
723 				size_t newsize, oldsize;
724 
725 				newsize = newlen * sizeof(*lists);
726 				oldsize = listcount * sizeof(*lists);
727 				tmp = isc_mem_get(mctx, newsize);
728 				if (listcount != 0) {
729 					memmove(tmp, lists, oldsize);
730 					isc_mem_put(mctx, lists, oldsize);
731 				}
732 				lists = tmp;
733 				listcount = newlen;
734 			}
735 			/* Seen? */
736 			for (j = 0; j < l; j++) {
737 				if (strcasecmp(lists[j].name, listname) == 0) {
738 					break;
739 				}
740 			}
741 			if (j < l) {
742 				continue;
743 			}
744 			list = NULL;
745 			tresult = named_config_getremotesdef(config, listtype,
746 							     listname, &list);
747 			if (tresult == ISC_R_NOTFOUND) {
748 				cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR,
749 					    "%s \"%s\" not found", listtype,
750 					    listname);
751 
752 				result = tresult;
753 				goto cleanup;
754 			}
755 			if (tresult != ISC_R_SUCCESS) {
756 				goto cleanup;
757 			}
758 			lists[l++].name = listname;
759 			/* Grow stack? */
760 			if (stackcount == pushed) {
761 				void *tmp;
762 				uint32_t newlen = stackcount + 16;
763 				size_t newsize, oldsize;
764 
765 				newsize = newlen * sizeof(*stack);
766 				oldsize = stackcount * sizeof(*stack);
767 				tmp = isc_mem_get(mctx, newsize);
768 				if (stackcount != 0) {
769 					memmove(tmp, stack, oldsize);
770 					isc_mem_put(mctx, stack, oldsize);
771 				}
772 				stack = tmp;
773 				stackcount = newlen;
774 			}
775 			/*
776 			 * We want to resume processing this list on the
777 			 * next element.
778 			 */
779 			stack[pushed].element = cfg_list_next(element);
780 			stack[pushed].port = port;
781 			stack[pushed].dscp = dscp;
782 			pushed++;
783 			goto newlist;
784 		}
785 
786 		if (i == addrcount) {
787 			void *tmp;
788 			uint32_t newlen = addrcount + 16;
789 			size_t newsize, oldsize;
790 
791 			newsize = newlen * sizeof(isc_sockaddr_t);
792 			oldsize = addrcount * sizeof(isc_sockaddr_t);
793 			tmp = isc_mem_get(mctx, newsize);
794 			if (addrcount != 0) {
795 				memmove(tmp, addrs, oldsize);
796 				isc_mem_put(mctx, addrs, oldsize);
797 			}
798 			addrs = tmp;
799 			addrcount = newlen;
800 
801 			newsize = newlen * sizeof(isc_dscp_t);
802 			oldsize = dscpcount * sizeof(isc_dscp_t);
803 			tmp = isc_mem_get(mctx, newsize);
804 			if (dscpcount != 0) {
805 				memmove(tmp, dscps, oldsize);
806 				isc_mem_put(mctx, dscps, oldsize);
807 			}
808 			dscps = tmp;
809 			dscpcount = newlen;
810 
811 			newsize = newlen * sizeof(dns_name_t *);
812 			oldsize = keycount * sizeof(dns_name_t *);
813 			tmp = isc_mem_get(mctx, newsize);
814 			if (keycount != 0) {
815 				memmove(tmp, keys, oldsize);
816 				isc_mem_put(mctx, keys, oldsize);
817 			}
818 			keys = tmp;
819 			keycount = newlen;
820 		}
821 
822 		addrs[i] = *cfg_obj_assockaddr(addr);
823 		if (isc_sockaddr_getport(&addrs[i]) == 0) {
824 			isc_sockaddr_setport(&addrs[i], port);
825 		}
826 		dscps[i] = cfg_obj_getdscp(addr);
827 		if (dscps[i] == -1) {
828 			dscps[i] = dscp;
829 		}
830 		keys[i] = NULL;
831 		i++; /* Increment here so that cleanup on error works. */
832 		if (!cfg_obj_isstring(key)) {
833 			continue;
834 		}
835 		keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t));
836 		dns_name_init(keys[i - 1], NULL);
837 
838 		keystr = cfg_obj_asstring(key);
839 		isc_buffer_constinit(&b, keystr, strlen(keystr));
840 		isc_buffer_add(&b, strlen(keystr));
841 		dns_fixedname_init(&fname);
842 		result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
843 					   dns_rootname, 0, NULL);
844 		if (result != ISC_R_SUCCESS) {
845 			goto cleanup;
846 		}
847 		dns_name_dup(dns_fixedname_name(&fname), mctx, keys[i - 1]);
848 	}
849 	if (pushed != 0) {
850 		pushed--;
851 		element = stack[pushed].element;
852 		port = stack[pushed].port;
853 		dscp = stack[pushed].dscp;
854 		goto resume;
855 	}
856 	if (i < addrcount) {
857 		void *tmp;
858 		size_t newsize, oldsize;
859 
860 		newsize = i * sizeof(isc_sockaddr_t);
861 		oldsize = addrcount * sizeof(isc_sockaddr_t);
862 		if (i != 0) {
863 			tmp = isc_mem_get(mctx, newsize);
864 			memmove(tmp, addrs, newsize);
865 		} else {
866 			tmp = NULL;
867 		}
868 		isc_mem_put(mctx, addrs, oldsize);
869 		addrs = tmp;
870 		addrcount = i;
871 
872 		newsize = i * sizeof(isc_dscp_t);
873 		oldsize = dscpcount * sizeof(isc_dscp_t);
874 		if (i != 0) {
875 			tmp = isc_mem_get(mctx, newsize);
876 			memmove(tmp, dscps, newsize);
877 		} else {
878 			tmp = NULL;
879 		}
880 		isc_mem_put(mctx, dscps, oldsize);
881 		dscps = tmp;
882 		dscpcount = i;
883 
884 		newsize = i * sizeof(dns_name_t *);
885 		oldsize = keycount * sizeof(dns_name_t *);
886 		if (i != 0) {
887 			tmp = isc_mem_get(mctx, newsize);
888 			memmove(tmp, keys, newsize);
889 		} else {
890 			tmp = NULL;
891 		}
892 		isc_mem_put(mctx, keys, oldsize);
893 		keys = tmp;
894 		keycount = i;
895 	}
896 
897 	if (lists != NULL) {
898 		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
899 	}
900 	if (stack != NULL) {
901 		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
902 	}
903 
904 	INSIST(dscpcount == addrcount);
905 	INSIST(keycount == addrcount);
906 	INSIST(keycount == dscpcount);
907 
908 	ipkl->addrs = addrs;
909 	ipkl->dscps = dscps;
910 	ipkl->keys = keys;
911 	ipkl->count = addrcount;
912 	ipkl->allocated = addrcount;
913 
914 	return (ISC_R_SUCCESS);
915 
916 cleanup:
917 	if (addrs != NULL) {
918 		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
919 	}
920 	if (dscps != NULL) {
921 		isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t));
922 	}
923 	if (keys != NULL) {
924 		for (j = 0; j < i; j++) {
925 			if (keys[j] == NULL) {
926 				continue;
927 			}
928 			if (dns_name_dynamic(keys[j])) {
929 				dns_name_free(keys[j], mctx);
930 			}
931 			isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
932 		}
933 		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
934 	}
935 	if (lists != NULL) {
936 		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
937 	}
938 	if (stack != NULL) {
939 		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
940 	}
941 	return (result);
942 }
943 
944 isc_result_t
945 named_config_getport(const cfg_obj_t *config, in_port_t *portp) {
946 	const cfg_obj_t *maps[3];
947 	const cfg_obj_t *options = NULL;
948 	const cfg_obj_t *portobj = NULL;
949 	isc_result_t result;
950 	int i;
951 
952 	(void)cfg_map_get(config, "options", &options);
953 	i = 0;
954 	if (options != NULL) {
955 		maps[i++] = options;
956 	}
957 	maps[i++] = named_g_defaults;
958 	maps[i] = NULL;
959 
960 	result = named_config_get(maps, "port", &portobj);
961 	INSIST(result == ISC_R_SUCCESS);
962 	if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
963 		cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
964 			    "port '%u' out of range",
965 			    cfg_obj_asuint32(portobj));
966 		return (ISC_R_RANGE);
967 	}
968 	*portp = (in_port_t)cfg_obj_asuint32(portobj);
969 	return (ISC_R_SUCCESS);
970 }
971 
972 isc_result_t
973 named_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) {
974 	const cfg_obj_t *options = NULL;
975 	const cfg_obj_t *dscpobj = NULL;
976 	isc_result_t result;
977 
978 	(void)cfg_map_get(config, "options", &options);
979 	if (options == NULL) {
980 		return (ISC_R_SUCCESS);
981 	}
982 
983 	result = cfg_map_get(options, "dscp", &dscpobj);
984 	if (result != ISC_R_SUCCESS || dscpobj == NULL) {
985 		*dscpp = -1;
986 		return (ISC_R_SUCCESS);
987 	}
988 	if (cfg_obj_asuint32(dscpobj) >= 64) {
989 		cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
990 			    "dscp '%u' out of range",
991 			    cfg_obj_asuint32(dscpobj));
992 		return (ISC_R_RANGE);
993 	}
994 	*dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
995 	return (ISC_R_SUCCESS);
996 }
997 
998 struct keyalgorithms {
999 	const char *str;
1000 	enum {
1001 		hmacnone,
1002 		hmacmd5,
1003 		hmacsha1,
1004 		hmacsha224,
1005 		hmacsha256,
1006 		hmacsha384,
1007 		hmacsha512
1008 	} hmac;
1009 	unsigned int type;
1010 	uint16_t size;
1011 } algorithms[] = { { "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 },
1012 		   { "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 },
1013 		   { "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 },
1014 		   { "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 },
1015 		   { "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 },
1016 		   { "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 },
1017 		   { "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 },
1018 		   { "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 },
1019 		   { NULL, hmacnone, DST_ALG_UNKNOWN, 0 } };
1020 
1021 isc_result_t
1022 named_config_getkeyalgorithm(const char *str, const dns_name_t **name,
1023 			     uint16_t *digestbits) {
1024 	return (named_config_getkeyalgorithm2(str, name, NULL, digestbits));
1025 }
1026 
1027 isc_result_t
1028 named_config_getkeyalgorithm2(const char *str, const dns_name_t **name,
1029 			      unsigned int *typep, uint16_t *digestbits) {
1030 	int i;
1031 	size_t len = 0;
1032 	uint16_t bits;
1033 	isc_result_t result;
1034 
1035 	for (i = 0; algorithms[i].str != NULL; i++) {
1036 		len = strlen(algorithms[i].str);
1037 		if (strncasecmp(algorithms[i].str, str, len) == 0 &&
1038 		    (str[len] == '\0' ||
1039 		     (algorithms[i].size != 0 && str[len] == '-')))
1040 		{
1041 			break;
1042 		}
1043 	}
1044 	if (algorithms[i].str == NULL) {
1045 		return (ISC_R_NOTFOUND);
1046 	}
1047 	if (str[len] == '-') {
1048 		result = isc_parse_uint16(&bits, str + len + 1, 10);
1049 		if (result != ISC_R_SUCCESS) {
1050 			return (result);
1051 		}
1052 		if (bits > algorithms[i].size) {
1053 			return (ISC_R_RANGE);
1054 		}
1055 	} else if (algorithms[i].size == 0) {
1056 		bits = 128;
1057 	} else {
1058 		bits = algorithms[i].size;
1059 	}
1060 
1061 	if (name != NULL) {
1062 		switch (algorithms[i].hmac) {
1063 		case hmacmd5:
1064 			*name = dns_tsig_hmacmd5_name;
1065 			break;
1066 		case hmacsha1:
1067 			*name = dns_tsig_hmacsha1_name;
1068 			break;
1069 		case hmacsha224:
1070 			*name = dns_tsig_hmacsha224_name;
1071 			break;
1072 		case hmacsha256:
1073 			*name = dns_tsig_hmacsha256_name;
1074 			break;
1075 		case hmacsha384:
1076 			*name = dns_tsig_hmacsha384_name;
1077 			break;
1078 		case hmacsha512:
1079 			*name = dns_tsig_hmacsha512_name;
1080 			break;
1081 		default:
1082 			UNREACHABLE();
1083 		}
1084 	}
1085 	if (typep != NULL) {
1086 		*typep = algorithms[i].type;
1087 	}
1088 	if (digestbits != NULL) {
1089 		*digestbits = bits;
1090 	}
1091 	return (ISC_R_SUCCESS);
1092 }
1093