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/grammar.h>
31
#include <isccfg/namedconf.h>
32 33 34 35

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

40 41
#include <dst/dst.h>

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

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

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

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

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

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

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

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

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

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

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

		}
	}
}

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

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

	return (i);
}

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

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

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

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

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

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

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

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

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

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

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

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

528 529 530 531 532
	return (ISC_R_SUCCESS);
}

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

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

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

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

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

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

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

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

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

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

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

646 647
	result = ISC_R_NOMEMORY;

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

659 660
		addr = cfg_tuple_get(cfg_listelt_value(element),
				     "masterselement");
661 662
		key = cfg_tuple_get(cfg_listelt_value(element), "key");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	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
856

857
	INSIST(keycount == addrcount);
858

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

	return (ISC_R_SUCCESS);

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

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

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

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