config.c 25 KB
Newer Older
1
/*
2
 * Copyright (C) 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
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10 11
 */

12
/*! \file */
Brian Wellington's avatar
Brian Wellington committed
13 14

#include <config.h>
15 16 17 18 19 20

#include <stdlib.h>

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

28 29
#include <pk11/site.h>

30
#include <isccfg/namedconf.h>
31 32 33 34

#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
35
#include <dns/rdatatype.h>
Brian Wellington's avatar
Brian Wellington committed
36
#include <dns/tsig.h>
37 38
#include <dns/zone.h>

39 40
#include <dst/dst.h>

41 42 43
#include <named/config.h>
#include <named/globals.h>

Evan Hunt's avatar
Evan Hunt committed
44
#include <bind.keys.h>
45

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

"#\n\
Mark Andrews's avatar
Mark Andrews committed
255
#  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
256
#\n\
257 258
view \"_bind\" chaos {\n\
	recursion no;\n\
259
	notify no;\n\
260
	allow-new-zones no;\n\
Evan Hunt's avatar
Evan Hunt committed
261 262 263 264 265 266 267
\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\
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
\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\
283
\n\
284 285 286 287
	zone \"id.server\" chaos {\n\
		type master;\n\
		database \"_builtin id\";\n\
	};\n\
288
};\n\
289 290
"
"#\n\
Evan Hunt's avatar
Evan Hunt committed
291 292
#  Default trusted key(s), used if \n\
# \"dnssec-validation auto;\" is set and\n\
293 294
#  sysconfdir/bind.keys doesn't exist).\n\
#\n\
295
# BEGIN MANAGED KEYS\n"
296 297

/* Imported from bind.keys.h: */
298
MANAGED_KEYS
299

300
"# END MANAGED KEYS\n\
301
";
302 303 304 305 306 307 308

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);
309
	return (cfg_parse_buffer3(parser, &b, __FILE__, 0,
310
				  &cfg_type_namedconf, conf));
311 312 313
}

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

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

327
isc_result_t
328 329 330 331 332 333 334
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;
335 336 337 338 339 340
	int i;

	for (i = 0;; i++) {
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		checknames = NULL;
341
		if (cfg_map_get(maps[i], "check-names",
Automatic Updater's avatar
Automatic Updater committed
342
				&checknames) == ISC_R_SUCCESS) {
343 344 345 346 347 348 349 350 351 352 353 354
			/*
			 * 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");
355 356
				if (strcasecmp(cfg_obj_asstring(type),
					       which) == 0) {
357 358 359 360 361 362 363 364 365
					*obj = cfg_tuple_get(value, "mode");
					return (ISC_R_SUCCESS);
				}
			}

		}
	}
}

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

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

	return (i);
}

isc_result_t
378
ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
379
		   dns_rdataclass_t *classp) {
380
	isc_textregion_t r;
381
	isc_result_t result;
382 383

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

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

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

415
dns_zonetype_t
416
ns_config_getzonetype(const cfg_obj_t *zonetypeobj) {
417
	dns_zonetype_t ztype = dns_zone_none;
418
	const char *str;
419 420

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

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

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

	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
475 476 477 478 479 480 481 482 483 484 485
	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);
		}
486 487 488 489

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

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

	for (element = cfg_list_first(addrlist);
	     element != NULL;
	     element = cfg_list_next(element), i++)
	{
Evan Hunt's avatar
Evan Hunt committed
503
		const cfg_obj_t *addr;
504
		INSIST(i < count);
Evan Hunt's avatar
Evan Hunt committed
505 506 507 508 509 510 511 512 513
		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;
		}
514 515 516 517 518 519 520 521
		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
522 523 524
	if (dscpsp != NULL)
		*dscpsp = dscps;

525 526 527 528 529
	return (ISC_R_SUCCESS);
}

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

	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
	*addrsp = NULL;
Evan Hunt's avatar
Evan Hunt committed
537 538 539 540 541

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

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

	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)) {
558
		const cfg_obj_t *list;
559 560 561 562 563 564 565 566 567 568 569 570 571
		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);
}

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

597
	REQUIRE(ipkl != NULL);
598
	REQUIRE(ipkl->count == 0);
599 600 601
	REQUIRE(ipkl->addrs == NULL);
	REQUIRE(ipkl->keys == NULL);
	REQUIRE(ipkl->dscps == NULL);
602 603
	REQUIRE(ipkl->labels == NULL);
	REQUIRE(ipkl->allocated == 0);
604

605 606 607 608 609 610 611 612 613 614 615
	/*
	 * 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;

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

621 622 623 624 625
	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);
626 627
			result = ISC_R_RANGE;
			goto cleanup;
628 629 630 631
		}
		port = (in_port_t) val;
	}

Evan Hunt's avatar
Evan Hunt committed
632 633 634 635 636
	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));
637 638
			result = ISC_R_RANGE;
			goto cleanup;
Evan Hunt's avatar
Evan Hunt committed
639 640 641 642
		}
		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
	}

643 644
	result = ISC_R_NOMEMORY;

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

656 657
		addr = cfg_tuple_get(cfg_listelt_value(element),
				     "masterselement");
658 659
		key = cfg_tuple_get(cfg_listelt_value(element), "key");

660
		if (!cfg_obj_issockaddr(addr)) {
661
			const char *listname = cfg_obj_asstring(addr);
662 663 664 665
			isc_result_t tresult;

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

				newsize = newlen * sizeof(*lists);
				oldsize = listcount * sizeof(*lists);
672 673
				tmp = isc_mem_get(mctx, newsize);
				if (tmp == NULL)
674 675
					goto cleanup;
				if (listcount != 0) {
676
					memmove(tmp, lists, oldsize);
677 678
					isc_mem_put(mctx, lists, oldsize);
				}
679
				lists = tmp;
680 681 682 683
				listcount = newlen;
			}
			/* Seen? */
			for (j = 0; j < l; j++)
Mark Andrews's avatar
Mark Andrews committed
684
				if (strcasecmp(lists[j].name, listname) == 0)
685 686 687 688 689 690
					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
691
				    "masters \"%s\" not found", listname);
692 693 694 695 696 697

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

				newsize = newlen * sizeof(*stack);
				oldsize = stackcount * sizeof(*stack);
707 708
				tmp = isc_mem_get(mctx, newsize);
				if (tmp == NULL)
709 710
					goto cleanup;
				if (stackcount != 0) {
711
					memmove(tmp, stack, oldsize);
712 713
					isc_mem_put(mctx, stack, oldsize);
				}
714
				stack = tmp;
715 716 717 718 719 720 721 722
				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
723
			stack[pushed].dscp = dscp;
724 725 726 727 728
			pushed++;
			goto newlist;
		}

		if (i == addrcount) {
729
			void * tmp;
730 731 732 733 734
			isc_uint32_t newlen = addrcount + 16;
			size_t newsize, oldsize;

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

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

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

770 771 772
		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
773 774 775
		dscps[i] = cfg_obj_getdscp(addr);
		if (dscps[i] == -1)
			dscps[i] = dscp;
776
		keys[i] = NULL;
777 778
		i++;	/* Increment here so that cleanup on error works. */
		if (!cfg_obj_isstring(key))
779
			continue;
780 781
		keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t));
		if (keys[i - 1] == NULL)
782
			goto cleanup;
783
		dns_name_init(keys[i - 1], NULL);
Automatic Updater's avatar
Automatic Updater committed
784

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

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

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

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

	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
853

854
	INSIST(keycount == addrcount);
855

856 857 858 859
	ipkl->addrs = addrs;
	ipkl->dscps = dscps;
	ipkl->keys = keys;
	ipkl->count = addrcount;
860
	ipkl->allocated = addrcount;
861 862 863 864 865

	return (ISC_R_SUCCESS);

 cleanup:
	if (addrs != NULL)
866
		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
Evan Hunt's avatar
Evan Hunt committed
867 868
	if (dscps != NULL)
		isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t));
869
	if (keys != NULL) {
870
		for (j = 0; j < i; j++) {
871 872 873 874 875 876
			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));
		}
877
		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
878
	}
879 880 881 882
	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
883 884 885 886
	return (result);
}

isc_result_t
887 888 889 890
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;
891 892 893
	isc_result_t result;
	int i;

894
	(void)cfg_map_get(config, "options", &options);
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
	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
912

Evan Hunt's avatar
Evan Hunt committed
913 914 915 916 917 918 919
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);
920 921
	if (options == NULL)
		return (ISC_R_SUCCESS);
Evan Hunt's avatar
Evan Hunt committed
922

923
	result = cfg_map_get(options, "dscp", &dscpobj);
Mark Andrews's avatar
Mark Andrews committed