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