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