config.c 24.9 KB
Newer Older
1
/*
2
 * Copyright (C) 2001-2017  Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 8
 */

9
/*! \file */
Brian Wellington's avatar
Brian Wellington committed
10 11

#include <config.h>
12 13 14 15 16 17

#include <stdlib.h>

#include <isc/buffer.h>
#include <isc/log.h>
#include <isc/mem.h>
18
#include <isc/parseint.h>
19 20 21
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
Evan Hunt's avatar
Evan Hunt committed
22
#include <isc/string.h>
23 24
#include <isc/util.h>

25 26
#include <pk11/site.h>

27
#include <isccfg/namedconf.h>
28 29 30 31

#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
32
#include <dns/rdatatype.h>
Brian Wellington's avatar
Brian Wellington committed
33
#include <dns/tsig.h>
34 35
#include <dns/zone.h>

36 37
#include <dst/dst.h>

38 39 40
#include <named/config.h>
#include <named/globals.h>

Evan Hunt's avatar
Evan Hunt committed
41
#include <bind.keys.h>
42

43
/*% default configuration */
44 45
static char defaultconf[] = "\
options {\n\
46
	automatic-interface-scan yes;\n\
Evan Hunt's avatar
Evan Hunt committed
47
	bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
48
#	blackhole {none;};\n"
49 50 51 52 53
#if defined(HAVE_OPENSSL_AES) || defined(HAVE_OPENSSL_EVP_AES)
"	cookie-algorithm aes;\n"
#else
"	cookie-algorithm sha256;\n"
#endif
54 55
#ifndef WIN32
"	coresize default;\n\
Mark Andrews's avatar
Mark Andrews committed
56
	datasize default;\n"
57
#endif
Mark Andrews's avatar
Mark Andrews committed
58
"\
59
#	deallocate-on-exit <obsolete>;\n\
60 61
#	directory <none>\n\
	dump-file \"named_dump.db\";\n\
Mark Andrews's avatar
Mark Andrews committed
62 63 64 65 66 67
	edns-udp-size 4096;\n\
#	fake-iquery <obsolete>;\n"
#ifndef WIN32
"	files unlimited;\n"
#endif
"\
68
#	has-old-clients <obsolete>;\n\
69
	heartbeat-interval 60;\n\
70
#	host-statistics <obsolete>;\n\
71
	interface-interval 60;\n\
72
#	keep-response-order {none;};\n\
73
	listen-on {any;};\n\
74
	listen-on-v6 {any;};\n\
Mark Andrews's avatar
Mark Andrews committed
75
#	lock-file \"" NS_LOCALSTATEDIR "/run/named/named.lock\";\n\
76
	match-mapped-addresses no;\n\
77
	max-rsa-exponent-size 0; /* no limit */\n\
Mark Andrews's avatar
Mark Andrews committed
78
	max-udp-size 4096;\n\
79
	memstatistics-file \"named.memstats\";\n\
80
#	multiple-cnames <obsolete>;\n\
81
#	named-xfer <obsolete>;\n\
Mark Andrews's avatar
Mark Andrews committed
82 83
	nocookie-udp-size 4096;\n\
	notify-rate 20;\n\
Evan Hunt's avatar
Evan Hunt committed
84 85
	nta-lifetime 3600;\n\
	nta-recheck 300;\n\
86
#	pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
87
	port 53;\n\
Mark Andrews's avatar
Mark Andrews committed
88
	prefetch 2 9;\n"
89
#ifdef PATH_RANDOMDEV
Mark Andrews's avatar
Mark Andrews committed
90
"	random-device \"" PATH_RANDOMDEV "\";\n"
91
#endif
Mark Andrews's avatar
Mark Andrews committed
92
"	recursing-file \"named.recursing\";\n\
93
	recursive-clients 1000;\n\
Mark Andrews's avatar
Mark Andrews committed
94 95
	request-nsid false;\n\
	reserved-sockets 512;\n\
96
	resolver-query-timeout 10;\n\
97
	rrset-order { order random; };\n\
Mark Andrews's avatar
Mark Andrews committed
98 99
	secroots-file \"named.secroots\";\n\
	send-cookie true;\n\
100
#	serial-queries <obsolete>;\n\
101
	serial-query-rate 20;\n\
102
	server-id none;\n\
Mark Andrews's avatar
Mark Andrews committed
103 104 105 106 107 108 109
	session-keyalg hmac-sha256;\n\
#	session-keyfile \"" NS_LOCALSTATEDIR "/run/named/session.key\";\n\
	session-keyname local-ddns;\n"
#ifndef WIN32
"	stacksize default;\n"
#endif
"	startup-notify-rate 20;\n\
110
	statistics-file \"named.stats\";\n\
111
#	statistics-interval <obsolete>;\n\
112
	tcp-clients 150;\n\
113
	tcp-listen-queue 10;\n\
114 115
#	tkey-dhkey <none>\n\
#	tkey-domain <none>\n\
Mark Andrews's avatar
Mark Andrews committed
116
#	tkey-gssapi-credential <none>\n\
117
	transfer-message-size 20480;\n\
118 119
	transfers-in 10;\n\
	transfers-out 10;\n\
Mark Andrews's avatar
Mark Andrews committed
120
	transfers-per-ns 2;\n\
121
#	treat-cr-as-space <obsolete>;\n\
122
	trust-anchor-telemetry yes;\n\
123
#	use-id-pool <obsolete>;\n\
124
#	use-ixfr <obsolete>;\n\
125 126
\n\
	/* view */\n\
Mark Andrews's avatar
Mark Andrews committed
127 128 129 130 131
	acache-cleaning-interval 60;\n\
	acache-enable no;\n\
	additional-from-auth true;\n\
	additional-from-cache true;\n\
	allow-new-zones no;\n\
132
	allow-notify {none;};\n\
133
	allow-query-cache { localnets; localhost; };\n\
134
	allow-query-cache-on { any; };\n\
135
	allow-recursion { localnets; localhost; };\n\
136
	allow-recursion-on { any; };\n\
Mark Andrews's avatar
Mark Andrews committed
137
	allow-update-forwarding {none;};\n\
138
#	allow-v6-synthesis <obsolete>;\n\
139
	auth-nxdomain false;\n\
140
	check-dup-records warn;\n\
141
	check-mx warn;\n\
Mark Andrews's avatar
Mark Andrews committed
142 143 144
	check-names master fail;\n\
	check-names response ignore;\n\
	check-names slave warn;\n\
145
	check-spf warn;\n\
Mark Andrews's avatar
Mark Andrews committed
146
	cleaning-interval 0;  /* now meaningless */\n\
147
	clients-per-query 10;\n\
Mark Andrews's avatar
Mark Andrews committed
148 149 150
	dnssec-accept-expired no;\n\
	dnssec-enable yes;\n\
	dnssec-validation yes; \n"
Evan Hunt's avatar
Evan Hunt committed
151
#ifdef HAVE_DNSTAP
Mark Andrews's avatar
Mark Andrews committed
152
"	dnstap-identity hostname;\n"
Evan Hunt's avatar
Evan Hunt committed
153
#endif
Evan Hunt's avatar
Evan Hunt committed
154
"\
Mark Andrews's avatar
Mark Andrews committed
155 156 157 158
#	fetch-glue <obsolete>;\n\
	fetch-quota-params 100 0.1 0.3 0.7;\n\
	fetches-per-server 0;\n\
	fetches-per-zone 0;\n"
Evan Hunt's avatar
Evan Hunt committed
159
#ifdef ALLOW_FILTER_AAAA
160
"	filter-aaaa-on-v4 no;\n\
Evan Hunt's avatar
Evan Hunt committed
161
	filter-aaaa-on-v6 no;\n\
Mark Andrews's avatar
Mark Andrews committed
162
	filter-aaaa { any; };\n"
163
#endif
Mark Andrews's avatar
Mark Andrews committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
#ifdef HAVE_GEOIP
"	geoip-use-ecs yes;\n"
#endif
"	lame-ttl 600;\n"
#ifdef HAVE_LMDB
"	lmdb-mapsize 32M;\n"
#endif
"	max-acache-size 16M;\n\
	max-cache-size 90%;\n\
	max-cache-ttl 604800; /* 1 week */\n\
	max-clients-per-query 100;\n\
	max-ncache-ttl 10800; /* 3 hours */\n\
	max-recursion-depth 7;\n\
	max-recursion-queries 75;\n\
	message-compression yes;\n\
#	min-roots <obsolete>;\n\
	minimal-any false;\n\
	minimal-responses false;\n\
	notify-source *;\n\
	notify-source-v6 *;\n\
	nsec3-test-zone no;\n\
	provide-ixfr true;\n\
	query-source address *;\n\
	query-source-v6 address *;\n\
	recursion true;\n\
	request-expire true;\n\
	request-ixfr true;\n\
	require-server-cookie no;\n\
#	rfc2308-type1 <obsolete>;\n\
	servfail-ttl 1;\n\
#	sortlist <none>\n\
#	topology <none>\n\
	transfer-format many-answers;\n\
	v6-bias 50;\n\
	zero-no-soa-ttl-cache no;\n\
\n\
	/* zone */\n\
201
	allow-query {any;};\n\
202
	allow-query-on {any;};\n\
203 204
	allow-transfer {any;};\n\
#	also-notify <none>\n\
Mark Andrews's avatar
Mark Andrews committed
205 206 207 208 209 210 211
	alt-transfer-source *;\n\
	alt-transfer-source-v6 *;\n\
	check-integrity yes;\n\
	check-mx-cname warn;\n\
	check-sibling yes;\n\
	check-srv-cname warn;\n\
	check-wildcard yes;\n\
212
	dialup no;\n\
Mark Andrews's avatar
Mark Andrews committed
213 214 215 216
	dnssec-dnskey-kskonly no;\n\
	dnssec-loadkeys-interval 60;\n\
	dnssec-secure-to-insecure no;\n\
	dnssec-update-mode maintain;\n\
217 218
#	forward <none>\n\
#	forwarders <none>\n\
Mark Andrews's avatar
Mark Andrews committed
219 220
	inline-signing no;\n\
	ixfr-from-differences false;\n\
221
#	maintain-ixfr-base <obsolete>;\n\
222
#	max-ixfr-log-size <obsolete>\n\
Mark Andrews's avatar
Mark Andrews committed
223
	max-journal-size unlimited;\n\
224
	max-records 0;\n\
225
	max-refresh-time 2419200; /* 4 weeks */\n\
Mark Andrews's avatar
Mark Andrews committed
226 227 228 229 230
	max-retry-time 1209600; /* 2 weeks */\n\
	max-transfer-idle-in 60;\n\
	max-transfer-idle-out 60;\n\
	max-transfer-time-in 120;\n\
	max-transfer-time-out 120;\n\
231
	min-refresh-time 300;\n\
Mark Andrews's avatar
Mark Andrews committed
232
	min-retry-time 500;\n\
233
	multi-master no;\n\
Mark Andrews's avatar
Mark Andrews committed
234 235 236 237
	notify yes;\n\
	notify-delay 5;\n\
	notify-to-soa no;\n\
	serial-update-method increment;\n\
238 239
	sig-signing-nodes 100;\n\
	sig-signing-signatures 10;\n\
240
	sig-signing-type 65534;\n\
Mark Andrews's avatar
Mark Andrews committed
241 242 243
	sig-validity-interval 30; /* days */\n\
	transfer-source *;\n\
	transfer-source-v6 *;\n\
244
	try-tcp-refresh yes; /* BIND 8 compat */\n\
Mark Andrews's avatar
Mark Andrews committed
245 246 247
	update-check-ksk yes;\n\
	zero-no-soa-ttl yes;\n\
	zone-statistics terse;\n\
248
};\n\
Mark Andrews's avatar
Mark Andrews committed
249 250 251
"

"#\n\
Mark Andrews's avatar
Mark Andrews committed
252
#  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
253
#\n\
254 255
view \"_bind\" chaos {\n\
	recursion no;\n\
256
	notify no;\n\
257
	allow-new-zones no;\n\
Evan Hunt's avatar
Evan Hunt committed
258 259 260 261 262 263 264
\n\
	# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
	rate-limit {\n\
		responses-per-second 3;\n\
		slip 0;\n\
		min-table-size 10;\n\
	};\n\
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
\n\
	zone \"version.bind\" chaos {\n\
		type master;\n\
		database \"_builtin version\";\n\
	};\n\
\n\
	zone \"hostname.bind\" chaos {\n\
		type master;\n\
		database \"_builtin hostname\";\n\
	};\n\
\n\
	zone \"authors.bind\" chaos {\n\
		type master;\n\
		database \"_builtin authors\";\n\
	};\n\
280
\n\
281 282 283 284
	zone \"id.server\" chaos {\n\
		type master;\n\
		database \"_builtin id\";\n\
	};\n\
285
};\n\
286 287
"
"#\n\
Evan Hunt's avatar
Evan Hunt committed
288 289
#  Default trusted key(s), used if \n\
# \"dnssec-validation auto;\" is set and\n\
290 291
#  sysconfdir/bind.keys doesn't exist).\n\
#\n\
292
# BEGIN MANAGED KEYS\n"
293 294

/* Imported from bind.keys.h: */
295
MANAGED_KEYS
296

297
"# END MANAGED KEYS\n\
298
";
299 300 301 302 303 304 305

isc_result_t
ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
	isc_buffer_t b;

	isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1);
	isc_buffer_add(&b, sizeof(defaultconf) - 1);
306
	return (cfg_parse_buffer3(parser, &b, __FILE__, 0,
307
				  &cfg_type_namedconf, conf));
308 309 310
}

isc_result_t
Evan Hunt's avatar
Evan Hunt committed
311 312 313
ns_config_get(cfg_obj_t const * const *maps, const char *name,
	      const cfg_obj_t **obj)
{
314 315
	int i;

316
	for (i = 0;; i++) {
317 318 319 320 321 322 323
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
			return (ISC_R_SUCCESS);
	}
}

324
isc_result_t
325 326 327 328 329 330 331
ns_checknames_get(const cfg_obj_t **maps, const char *which,
		  const cfg_obj_t **obj)
{
	const cfg_listelt_t *element;
	const cfg_obj_t *checknames;
	const cfg_obj_t *type;
	const cfg_obj_t *value;
332 333 334 335 336 337
	int i;

	for (i = 0;; i++) {
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		checknames = NULL;
338
		if (cfg_map_get(maps[i], "check-names",
Automatic Updater's avatar
Automatic Updater committed
339
				&checknames) == ISC_R_SUCCESS) {
340 341 342 343 344 345 346 347 348 349 350 351
			/*
			 * Zone map entry is not a list.
			 */
			if (checknames != NULL && !cfg_obj_islist(checknames)) {
				*obj = checknames;
				return (ISC_R_SUCCESS);
			}
			for (element = cfg_list_first(checknames);
			     element != NULL;
			     element = cfg_list_next(element)) {
				value = cfg_listelt_value(element);
				type = cfg_tuple_get(value, "type");
352 353
				if (strcasecmp(cfg_obj_asstring(type),
					       which) == 0) {
354 355 356 357 358 359 360 361 362
					*obj = cfg_tuple_get(value, "mode");
					return (ISC_R_SUCCESS);
				}
			}

		}
	}
}

363
int
364 365
ns_config_listcount(const cfg_obj_t *list) {
	const cfg_listelt_t *e;
366 367 368 369 370 371 372 373 374
	int i = 0;

	for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e))
		i++;

	return (i);
}

isc_result_t
375
ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
376
		   dns_rdataclass_t *classp) {
377
	isc_textregion_t r;
378
	isc_result_t result;
379 380

	if (!cfg_obj_isstring(classobj)) {
381
		*classp = defclass;
382 383
		return (ISC_R_SUCCESS);
	}
384 385
	DE_CONST(cfg_obj_asstring(classobj), r.base);
	r.length = strlen(r.base);
386 387 388
	result = dns_rdataclass_fromtext(classp, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
389
			    "unknown class '%s'", r.base);
390
	return (result);
391 392
}

393
isc_result_t
394
ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
395 396 397 398 399 400 401 402
		   dns_rdatatype_t *typep) {
	isc_textregion_t r;
	isc_result_t result;

	if (!cfg_obj_isstring(typeobj)) {
		*typep = deftype;
		return (ISC_R_SUCCESS);
	}
403 404
	DE_CONST(cfg_obj_asstring(typeobj), r.base);
	r.length = strlen(r.base);
405 406 407
	result = dns_rdatatype_fromtext(typep, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR,
408
			    "unknown type '%s'", r.base);
409 410 411
	return (result);
}

412
dns_zonetype_t
413
ns_config_getzonetype(const cfg_obj_t *zonetypeobj) {
414
	dns_zonetype_t ztype = dns_zone_none;
415
	const char *str;
416 417

	str = cfg_obj_asstring(zonetypeobj);
418
	if (strcasecmp(str, "master") == 0)
419
		ztype = dns_zone_master;
420
	else if (strcasecmp(str, "slave") == 0)
421
		ztype = dns_zone_slave;
422
	else if (strcasecmp(str, "stub") == 0)
423
		ztype = dns_zone_stub;
424 425
	else if (strcasecmp(str, "static-stub") == 0)
		ztype = dns_zone_staticstub;
426 427
	else if (strcasecmp(str, "redirect") == 0)
		ztype = dns_zone_redirect;
428 429 430 431 432 433
	else
		INSIST(0);
	return (ztype);
}

isc_result_t
434
ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
435
		    in_port_t defport, isc_mem_t *mctx,
Evan Hunt's avatar
Evan Hunt committed
436 437
		    isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp,
		    isc_uint32_t *countp)
438 439
{
	int count, i = 0;
440
	const cfg_obj_t *addrlist;
Evan Hunt's avatar
Evan Hunt committed
441
	const cfg_obj_t *portobj, *dscpobj;
442
	const cfg_listelt_t *element;
443 444
	isc_sockaddr_t *addrs;
	in_port_t port;
Mark Andrews's avatar
Mark Andrews committed
445
	isc_dscp_t dscp = -1, *dscps = NULL;
446 447 448
	isc_result_t result;

	INSIST(addrsp != NULL && *addrsp == NULL);
Evan Hunt's avatar
Evan Hunt committed
449
	INSIST(dscpsp == NULL || *dscpsp == NULL);
450
	INSIST(countp != NULL);
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471

	addrlist = cfg_tuple_get(list, "addresses");
	count = ns_config_listcount(addrlist);

	portobj = cfg_tuple_get(list, "port");
	if (cfg_obj_isuint32(portobj)) {
		isc_uint32_t val = cfg_obj_asuint32(portobj);
		if (val > ISC_UINT16_MAX) {
			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
				    "port '%u' out of range", val);
			return (ISC_R_RANGE);
		}
		port = (in_port_t) val;
	} else if (defport != 0)
		port = defport;
	else {
		result = ns_config_getport(config, &port);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

Evan Hunt's avatar
Evan Hunt committed
472 473 474 475 476 477 478 479 480 481 482
	if (dscpsp != NULL) {
		dscpobj = cfg_tuple_get(list, "dscp");
		if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) {
			if (cfg_obj_asuint32(dscpobj) > 63) {
				cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
					    "dscp value '%u' is out of range",
					    cfg_obj_asuint32(dscpobj));
				return (ISC_R_RANGE);
			}
			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
		}
483 484 485 486

		dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t));
		if (dscps == NULL)
			return (ISC_R_NOMEMORY);
Evan Hunt's avatar
Evan Hunt committed
487 488
	}

489
	addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
490 491 492
	if (addrs == NULL) {
		if (dscps != NULL)
			isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t));
493
		return (ISC_R_NOMEMORY);
494
	}
495 496 497 498 499

	for (element = cfg_list_first(addrlist);
	     element != NULL;
	     element = cfg_list_next(element), i++)
	{
Evan Hunt's avatar
Evan Hunt committed
500
		const cfg_obj_t *addr;
501
		INSIST(i < count);
Evan Hunt's avatar
Evan Hunt committed
502 503 504 505 506 507 508 509 510
		addr = cfg_listelt_value(element);
		addrs[i] = *cfg_obj_assockaddr(addr);
		if (dscpsp != NULL) {
			isc_dscp_t innerdscp;
			innerdscp = cfg_obj_getdscp(addr);
			if (innerdscp == -1)
				innerdscp = dscp;
			dscps[i] = innerdscp;
		}
511 512 513 514 515 516 517 518
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
	}
	INSIST(i == count);

	*addrsp = addrs;
	*countp = count;

Evan Hunt's avatar
Evan Hunt committed
519 520 521
	if (dscpsp != NULL)
		*dscpsp = dscps;

522 523 524 525 526
	return (ISC_R_SUCCESS);
}

void
ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
Evan Hunt's avatar
Evan Hunt committed
527
		    isc_dscp_t **dscpsp, isc_uint32_t count)
528 529
{
	INSIST(addrsp != NULL && *addrsp != NULL);
Evan Hunt's avatar
Evan Hunt committed
530
	INSIST(dscpsp == NULL || *dscpsp != NULL);
531 532 533

	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
	*addrsp = NULL;
Evan Hunt's avatar
Evan Hunt committed
534 535 536 537 538

	if (dscpsp != NULL) {
		isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t));
		*dscpsp = NULL;
	}
539 540
}

541
static isc_result_t
542
get_masters_def(const cfg_obj_t *cctx, const char *name,
Automatic Updater's avatar
Automatic Updater committed
543
		const cfg_obj_t **ret)
544
{
545
	isc_result_t result;
546 547
	const cfg_obj_t *masters = NULL;
	const cfg_listelt_t *elt;
548 549 550 551 552 553 554

	result = cfg_map_get(cctx, "masters", &masters);
	if (result != ISC_R_SUCCESS)
		return (result);
	for (elt = cfg_list_first(masters);
	     elt != NULL;
	     elt = cfg_list_next(elt)) {
555
		const cfg_obj_t *list;
556 557 558 559 560 561 562 563 564 565 566 567 568
		const char *listname;

		list = cfg_listelt_value(elt);
		listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));

		if (strcasecmp(listname, name) == 0) {
			*ret = list;
			return (ISC_R_SUCCESS);
		}
	}
	return (ISC_R_NOTFOUND);
}

569
isc_result_t
570
ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
571
			  isc_mem_t *mctx, dns_ipkeylist_t *ipkl)
572
{
Evan Hunt's avatar
Evan Hunt committed
573
	isc_uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0;
574 575
	isc_uint32_t listcount = 0, l = 0, j;
	isc_uint32_t stackcount = 0, pushed = 0;
576
	isc_result_t result;
577 578 579
	const cfg_listelt_t *element;
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj;
Evan Hunt's avatar
Evan Hunt committed
580
	const cfg_obj_t *dscpobj;
581
	in_port_t port;
582
	isc_dscp_t dscp = -1;
583 584
	dns_fixedname_t fname;
	isc_sockaddr_t *addrs = NULL;
Evan Hunt's avatar
Evan Hunt committed
585
	isc_dscp_t *dscps = NULL;
586
	dns_name_t **keys = NULL;
Mark Andrews's avatar
Mark Andrews committed
587
	struct { const char *name; } *lists = NULL;
588
	struct {
589
		const cfg_listelt_t *element;
590
		in_port_t port;
Evan Hunt's avatar
Evan Hunt committed
591
		isc_dscp_t dscp;
592
	} *stack = NULL;
593

594
	REQUIRE(ipkl != NULL);
595
	REQUIRE(ipkl->count == 0);
596 597 598
	REQUIRE(ipkl->addrs == NULL);
	REQUIRE(ipkl->keys == NULL);
	REQUIRE(ipkl->dscps == NULL);
599 600
	REQUIRE(ipkl->labels == NULL);
	REQUIRE(ipkl->allocated == 0);
601

602 603 604 605 606 607 608 609 610 611 612
	/*
	 * Get system defaults.
	 */
	result = ns_config_getport(config, &port);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	result = ns_config_getdscp(config, &dscp);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

613
 newlist:
614 615
	addrlist = cfg_tuple_get(list, "addresses");
	portobj = cfg_tuple_get(list, "port");
Evan Hunt's avatar
Evan Hunt committed
616 617
	dscpobj = cfg_tuple_get(list, "dscp");

618 619 620 621 622
	if (cfg_obj_isuint32(portobj)) {
		isc_uint32_t val = cfg_obj_asuint32(portobj);
		if (val > ISC_UINT16_MAX) {
			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
				    "port '%u' out of range", val);
623 624
			result = ISC_R_RANGE;
			goto cleanup;
625 626 627 628
		}
		port = (in_port_t) val;
	}

Evan Hunt's avatar
Evan Hunt committed
629 630 631 632 633
	if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) {
		if (cfg_obj_asuint32(dscpobj) > 63) {
			cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
				    "dscp value '%u' is out of range",
				    cfg_obj_asuint32(dscpobj));
634 635
			result = ISC_R_RANGE;
			goto cleanup;
Evan Hunt's avatar
Evan Hunt committed
636 637 638 639
		}
		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
	}

640 641
	result = ISC_R_NOMEMORY;

642 643 644
	element = cfg_list_first(addrlist);
 resume:
	for ( ;
645
	     element != NULL;
646
	     element = cfg_list_next(element))
647
	{
648 649
		const cfg_obj_t *addr;
		const cfg_obj_t *key;
650
		const char *keystr;
651 652
		isc_buffer_t b;

653 654
		addr = cfg_tuple_get(cfg_listelt_value(element),
				     "masterselement");
655 656
		key = cfg_tuple_get(cfg_listelt_value(element), "key");

657
		if (!cfg_obj_issockaddr(addr)) {
658
			const char *listname = cfg_obj_asstring(addr);
659 660 661 662
			isc_result_t tresult;

			/* Grow lists? */
			if (listcount == l) {
663
				void * tmp;
664 665 666 667 668
				isc_uint32_t newlen = listcount + 16;
				size_t newsize, oldsize;

				newsize = newlen * sizeof(*lists);
				oldsize = listcount * sizeof(*lists);
669 670
				tmp = isc_mem_get(mctx, newsize);
				if (tmp == NULL)
671 672
					goto cleanup;
				if (listcount != 0) {
673
					memmove(tmp, lists, oldsize);
674 675
					isc_mem_put(mctx, lists, oldsize);
				}
676
				lists = tmp;
677 678 679 680
				listcount = newlen;
			}
			/* Seen? */
			for (j = 0; j < l; j++)
Mark Andrews's avatar
Mark Andrews committed
681
				if (strcasecmp(lists[j].name, listname) == 0)
682 683 684 685 686 687
					break;
			if (j < l)
				continue;
			tresult = get_masters_def(config, listname, &list);
			if (tresult == ISC_R_NOTFOUND) {
				cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR,
Automatic Updater's avatar
Automatic Updater committed
688
				    "masters \"%s\" not found", listname);
689 690 691 692 693 694

				result = tresult;
				goto cleanup;
			}
			if (tresult != ISC_R_SUCCESS)
				goto cleanup;
Mark Andrews's avatar
Mark Andrews committed
695
			lists[l++].name = listname;
696 697
			/* Grow stack? */
			if (stackcount == pushed) {
698
				void * tmp;
699 700 701 702 703
				isc_uint32_t newlen = stackcount + 16;
				size_t newsize, oldsize;

				newsize = newlen * sizeof(*stack);
				oldsize = stackcount * sizeof(*stack);
704 705
				tmp = isc_mem_get(mctx, newsize);
				if (tmp == NULL)
706 707
					goto cleanup;
				if (stackcount != 0) {
708
					memmove(tmp, stack, oldsize);
709 710
					isc_mem_put(mctx, stack, oldsize);
				}
711
				stack = tmp;
712 713 714 715 716 717 718 719
				stackcount = newlen;
			}
			/*
			 * We want to resume processing this list on the
			 * next element.
			 */
			stack[pushed].element = cfg_list_next(element);
			stack[pushed].port = port;
Evan Hunt's avatar
Evan Hunt committed
720
			stack[pushed].dscp = dscp;
721 722 723 724 725
			pushed++;
			goto newlist;
		}

		if (i == addrcount) {
726
			void * tmp;
727 728 729 730 731
			isc_uint32_t newlen = addrcount + 16;
			size_t newsize, oldsize;

			newsize = newlen * sizeof(isc_sockaddr_t);
			oldsize = addrcount * sizeof(isc_sockaddr_t);
732 733
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
734 735
				goto cleanup;
			if (addrcount != 0) {
736
				memmove(tmp, addrs, oldsize);
737 738
				isc_mem_put(mctx, addrs, oldsize);
			}
739
			addrs = tmp;
740 741
			addrcount = newlen;

Evan Hunt's avatar
Evan Hunt committed
742 743
			newsize = newlen * sizeof(isc_dscp_t);
			oldsize = dscpcount * sizeof(isc_dscp_t);
744 745
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
Evan Hunt's avatar
Evan Hunt committed
746 747
				goto cleanup;
			if (dscpcount != 0) {
748
				memmove(tmp, dscps, oldsize);
Evan Hunt's avatar
Evan Hunt committed
749 750
				isc_mem_put(mctx, dscps, oldsize);
			}
751
			dscps = tmp;
Evan Hunt's avatar
Evan Hunt committed
752 753
			dscpcount = newlen;

754 755
			newsize = newlen * sizeof(dns_name_t *);
			oldsize = keycount * sizeof(dns_name_t *);
756 757
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
758 759
				goto cleanup;
			if (keycount != 0) {
760
				memmove(tmp, keys, oldsize);
761
				isc_mem_put(mctx, keys, oldsize);
762
			}
763
			keys = tmp;
764 765 766
			keycount = newlen;
		}

767 768 769
		addrs[i] = *cfg_obj_assockaddr(addr);
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
Evan Hunt's avatar
Evan Hunt committed
770 771 772
		dscps[i] = cfg_obj_getdscp(addr);
		if (dscps[i] == -1)
			dscps[i] = dscp;
773
		keys[i] = NULL;
774 775
		i++;	/* Increment here so that cleanup on error works. */
		if (!cfg_obj_isstring(key))
776
			continue;
777 778
		keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t));
		if (keys[i - 1] == NULL)
779
			goto cleanup;
780
		dns_name_init(keys[i - 1], NULL);
Automatic Updater's avatar
Automatic Updater committed
781

782
		keystr = cfg_obj_asstring(key);
783
		isc_buffer_constinit(&b, keystr, strlen(keystr));
784 785 786
		isc_buffer_add(&b, strlen(keystr));
		dns_fixedname_init(&fname);
		result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
787
					   dns_rootname, 0, NULL);
788 789 790
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		result = dns_name_dup(dns_fixedname_name(&fname), mctx,
791
				      keys[i - 1]);
792 793
		if (result != ISC_R_SUCCESS)
			goto cleanup;
794 795 796 797 798
	}
	if (pushed != 0) {
		pushed--;
		element = stack[pushed].element;
		port = stack[pushed].port;
Evan Hunt's avatar
Evan Hunt committed
799
		dscp = stack[pushed].dscp;
800 801 802
		goto resume;
	}
	if (i < addrcount) {
803
		void * tmp;
804 805 806 807 808
		size_t newsize, oldsize;

		newsize = i * sizeof(isc_sockaddr_t);
		oldsize = addrcount * sizeof(isc_sockaddr_t);
		if (i != 0) {
809 810
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
811
				goto cleanup;
812
			memmove(tmp, addrs, newsize);
813
		} else
814
			tmp = NULL;
815
		isc_mem_put(mctx, addrs, oldsize);
816
		addrs = tmp;
817 818
		addrcount = i;

Evan Hunt's avatar
Evan Hunt committed
819 820 821
		newsize = i * sizeof(isc_dscp_t);
		oldsize = dscpcount * sizeof(isc_dscp_t);
		if (i != 0) {
822 823
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
Evan Hunt's avatar
Evan Hunt committed
824
				goto cleanup;
825
			memmove(tmp, dscps, newsize);
Evan Hunt's avatar
Evan Hunt committed
826
		} else
827
			tmp = NULL;
Evan Hunt's avatar
Evan Hunt committed
828
		isc_mem_put(mctx, dscps, oldsize);
829
		dscps = tmp;
Evan Hunt's avatar
Evan Hunt committed
830 831
		dscpcount = i;

832 833 834
		newsize = i * sizeof(dns_name_t *);
		oldsize = keycount * sizeof(dns_name_t *);
		if (i != 0) {
835 836
			tmp = isc_mem_get(mctx, newsize);
			if (tmp == NULL)
837
				goto cleanup;
838
			memmove(tmp, keys,  newsize);
839
		} else
840
			tmp = NULL;
841
		isc_mem_put(mctx, keys, oldsize);
842
		keys = tmp;
843
		keycount = i;
844
	}
845 846 847 848 849

	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
Automatic Updater's avatar
Automatic Updater committed
850

851
	INSIST(keycount == addrcount);
852

853 854 855 856
	ipkl->addrs = addrs;
	ipkl->dscps = dscps;
	ipkl->keys = keys;
	ipkl->count = addrcount;
857
	ipkl->allocated = addrcount;
858 859 860 861 862

	return (ISC_R_SUCCESS);

 cleanup:
	if (addrs != NULL)
863
		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
Evan Hunt's avatar
Evan Hunt committed
864 865
	if (dscps != NULL)
		isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t));
866
	if (keys != NULL) {
867
		for (j = 0; j < i; j++) {
868 869 870 871 872 873
			if (keys[j] == NULL)
				continue;
			if (dns_name_dynamic(keys[j]))
				dns_name_free(keys[j], mctx);
			isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
		}
874
		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
875
	}
876 877 878 879
	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
880 881 882 883
	return (result);
}

isc_result_t
884 885 886 887
ns_config_getport(const cfg_obj_t *config, in_port_t *portp) {
	const cfg_obj_t *maps[3];
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *portobj = NULL;
888 889 890
	isc_result_t result;
	int i;

891
	(void)cfg_map_get(config, "options", &options);
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
	i = 0;
	if (options != NULL)
		maps[i++] = options;
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

	result = ns_config_get(maps, "port", &portobj);
	INSIST(result == ISC_R_SUCCESS);
	if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
		cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
			    "port '%u' out of range",
			    cfg_obj_asuint32(portobj));
		return (ISC_R_RANGE);
	}
	*portp = (in_port_t)cfg_obj_asuint32(portobj);
	return (ISC_R_SUCCESS);
}
Brian Wellington's avatar
Brian Wellington committed
909

Evan Hunt's avatar
Evan Hunt committed
910 911 912 913 914 915 916
isc_result_t
ns_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) {
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *dscpobj = NULL;
	isc_result_t result;

	(void)cfg_map_get(config, "options", &options);
917 918
	if (options == NULL)
		return (ISC_R_SUCCESS);
Evan Hunt's avatar
Evan Hunt committed
919

920
	result = cfg_map_get(options, "dscp", &dscpobj);
Mark Andrews's avatar
Mark Andrews committed
921
	if (result != ISC_R_SUCCESS || dscpobj == NULL) {
Evan Hunt's avatar
Evan Hunt committed
922 923