config.c 25.1 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
#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\
196
	root-key-sentinel yes;\n\
Mark Andrews's avatar
Mark Andrews committed
197 198 199 200 201 202 203 204
	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\
205
	allow-query {any;};\n\
206
	allow-query-on {any;};\n\
207 208
	allow-transfer {any;};\n\
#	also-notify <none>\n\
Mark Andrews's avatar
Mark Andrews committed
209 210 211 212 213 214 215
	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\
216
	dialup no;\n\
Mark Andrews's avatar
Mark Andrews committed
217 218 219 220
	dnssec-dnskey-kskonly no;\n\
	dnssec-loadkeys-interval 60;\n\
	dnssec-secure-to-insecure no;\n\
	dnssec-update-mode maintain;\n\
221 222
#	forward <none>\n\
#	forwarders <none>\n\
Mark Andrews's avatar
Mark Andrews committed
223 224
	inline-signing no;\n\
	ixfr-from-differences false;\n\
225
#	maintain-ixfr-base <obsolete>;\n\
226
#	max-ixfr-log-size <obsolete>\n\
Mark Andrews's avatar
Mark Andrews committed
227
	max-journal-size unlimited;\n\
228
	max-records 0;\n\
229
	max-refresh-time 2419200; /* 4 weeks */\n\
Mark Andrews's avatar
Mark Andrews committed
230 231 232 233 234
	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\
235
	min-refresh-time 300;\n\
Mark Andrews's avatar
Mark Andrews committed
236
	min-retry-time 500;\n\
237
	multi-master no;\n\
Mark Andrews's avatar
Mark Andrews committed
238 239 240 241
	notify yes;\n\
	notify-delay 5;\n\
	notify-to-soa no;\n\
	serial-update-method increment;\n\
242 243
	sig-signing-nodes 100;\n\
	sig-signing-signatures 10;\n\
244
	sig-signing-type 65534;\n\
Mark Andrews's avatar
Mark Andrews committed
245 246 247
	sig-validity-interval 30; /* days */\n\
	transfer-source *;\n\
	transfer-source-v6 *;\n\
248
	try-tcp-refresh yes; /* BIND 8 compat */\n\
Mark Andrews's avatar
Mark Andrews committed
249 250 251
	update-check-ksk yes;\n\
	zero-no-soa-ttl yes;\n\
	zone-statistics terse;\n\
252
};\n\
Mark Andrews's avatar
Mark Andrews committed
253 254 255
"

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

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

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

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

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

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

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

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

		}
	}
}

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

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

	return (i);
}

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

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

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

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

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

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

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

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

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

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

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

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

526 527 528 529 530
	return (ISC_R_SUCCESS);
}

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

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

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

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

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

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

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

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

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

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

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

644 645
	result = ISC_R_NOMEMORY;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	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
854

855
	INSIST(keycount == addrcount);
856

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

	return (ISC_R_SUCCESS);

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

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

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

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

Mark Andrews's avatar