server.c 400 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 */
David Lawrence's avatar
David Lawrence committed
13

14 15
#include <config.h>

16
#include <inttypes.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
#include <unistd.h>
20
#include <limits.h>
21 22 23
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
24

25
#include <isc/aes.h>
26
#include <isc/app.h>
27
#include <isc/base64.h>
Evan Hunt's avatar
Evan Hunt committed
28
#include <isc/commandline.h>
29
#include <isc/dir.h>
30
#include <isc/file.h>
31
#include <isc/hash.h>
32
#include <isc/hex.h>
33
#include <isc/hmac.h>
34
#include <isc/httpd.h>
35
#include <isc/lex.h>
36
#include <isc/meminfo.h>
37
#include <isc/nonce.h>
38
#include <isc/parseint.h>
Evan Hunt's avatar
Evan Hunt committed
39
#include <isc/platform.h>
40
#include <isc/portset.h>
41
#include <isc/print.h>
42
#include <isc/refcount.h>
43
#include <isc/resource.h>
Mark Andrews's avatar
Mark Andrews committed
44
#include <isc/socket.h>
45
#include <isc/stat.h>
46
#include <isc/stats.h>
47
#include <isc/stdio.h>
48
#include <isc/string.h>
49
#include <isc/task.h>
50
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
51
#include <isc/util.h>
52
#include <isc/xml.h>
53

Evan Hunt's avatar
Evan Hunt committed
54
#include <isccfg/grammar.h>
55
#include <isccfg/namedconf.h>
56 57

#include <bind9/check.h>
58

59
#include <dns/adb.h>
Evan Hunt's avatar
Evan Hunt committed
60
#include <dns/badcache.h>
61
#include <dns/cache.h>
62
#include <dns/catz.h>
63
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
64
#include <dns/dispatch.h>
65
#include <dns/dlz.h>
66
#include <dns/dnsrps.h>
67
#include <dns/dns64.h>
Evan Hunt's avatar
Evan Hunt committed
68
#include <dns/dyndb.h>
69
#include <dns/events.h>
70
#include <dns/forward.h>
71
#include <dns/fixedname.h>
72
#include <dns/journal.h>
73
#include <dns/keytable.h>
74
#include <dns/keyvalues.h>
75
#include <dns/lib.h>
76
#include <dns/master.h>
77
#include <dns/masterdump.h>
Evan Hunt's avatar
Evan Hunt committed
78
#include <dns/nta.h>
79
#include <dns/order.h>
80
#include <dns/peer.h>
81
#include <dns/portlist.h>
82
#include <dns/private.h>
83
#include <dns/rbt.h>
84
#include <dns/rdataclass.h>
85
#include <dns/rdatalist.h>
86
#include <dns/rdataset.h>
87
#include <dns/rdatastruct.h>
88
#include <dns/resolver.h>
89
#include <dns/rootns.h>
Evan Hunt's avatar
Evan Hunt committed
90
#include <dns/rriterator.h>
91
#include <dns/secalg.h>
92
#include <dns/soa.h>
93
#include <dns/stats.h>
94
#include <dns/tkey.h>
95
#include <dns/tsig.h>
Evan Hunt's avatar
Evan Hunt committed
96
#include <dns/ttl.h>
97
#include <dns/view.h>
98
#include <dns/zone.h>
99
#include <dns/zt.h>
100

101
#include <dst/dst.h>
102
#include <dst/result.h>
103

104 105 106 107
#include <ns/client.h>
#include <ns/listenlist.h>
#include <ns/interfacemgr.h>

108
#include <named/config.h>
109
#include <named/control.h>
110
#ifdef HAVE_GEOIP
Evan Hunt's avatar
Evan Hunt committed
111
#include <named/geoip.h>
112
#endif /* HAVE_GEOIP */
113
#include <named/log.h>
114
#include <named/logconf.h>
115
#include <named/main.h>
116
#include <named/os.h>
Bob Halley's avatar
Bob Halley committed
117
#include <named/server.h>
118
#include <named/statschannel.h>
119 120 121
#include <named/tkeyconf.h>
#include <named/tsigconf.h>
#include <named/zoneconf.h>
122
#ifdef HAVE_LIBSCF
123
#include <named/smf_globals.h>
124 125
#include <stdlib.h>
#endif
126 127 128 129 130 131 132 133 134 135 136

#ifdef HAVE_LMDB
#include <lmdb.h>
#define count_newzones count_newzones_db
#define configure_newzones configure_newzones_db
#define dumpzone dumpzone_db
#else  /* HAVE_LMDB */
#define count_newzones count_newzones_file
#define configure_newzones configure_newzones_file
#define dumpzone dumpzone_file
#endif /* HAVE_LMDB */
137

138 139 140 141
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

142 143 144 145
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif

146 147 148 149
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
#endif

150 151 152 153 154 155 156 157 158 159
#ifdef TUNE_LARGE
#define RESOLVER_NTASKS 523
#define UDPBUFFERS 32768
#define EXCLBUFFERS 32768
#else
#define RESOLVER_NTASKS 31
#define UDPBUFFERS 1000
#define EXCLBUFFERS 4096
#endif /* TUNE_LARGE */

160 161
#define MAX_TCP_TIMEOUT 65535

162
/*%
163 164 165 166
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
#define CHECK(op) \
167 168
	do { result = (op);					 \
	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
169 170
	} while (0)

171 172 173
#define TCHECK(op) \
	do { tresult = (op);					 \
		if (tresult != ISC_R_SUCCESS) {			 \
174
			isc_buffer_clear(*text);		 \
175 176 177 178
			goto cleanup;	 			 \
		}						 \
	} while (0)

179
#define CHECKM(op, msg) \
180
	do { result = (op);					  \
181
	       if (result != ISC_R_SUCCESS) {			  \
182 183 184
			isc_log_write(named_g_lctx,		  \
				      NAMED_LOGCATEGORY_GENERAL,	  \
				      NAMED_LOGMODULE_SERVER,	  \
185 186 187 188 189 190 191
				      ISC_LOG_ERROR,		  \
				      "%s: %s", msg,		  \
				      isc_result_totext(result)); \
			goto cleanup;				  \
		}						  \
	} while (0)						  \

Mark Andrews's avatar
Mark Andrews committed
192
#define CHECKMF(op, msg, file) \
193
	do { result = (op);					  \
Mark Andrews's avatar
Mark Andrews committed
194
	       if (result != ISC_R_SUCCESS) {			  \
195 196 197
			isc_log_write(named_g_lctx,		  \
				      NAMED_LOGCATEGORY_GENERAL,	  \
				      NAMED_LOGMODULE_SERVER,	  \
Mark Andrews's avatar
Mark Andrews committed
198 199 200 201 202 203 204
				      ISC_LOG_ERROR,		  \
				      "%s '%s': %s", msg, file,	  \
				      isc_result_totext(result)); \
			goto cleanup;				  \
		}						  \
	} while (0)						  \

205
#define CHECKFATAL(op, msg) \
206
	do { result = (op);					  \
207 208 209 210
	       if (result != ISC_R_SUCCESS)			  \
			fatal(msg, result);			  \
	} while (0)						  \

211 212 213 214 215 216
/*%
 * Maximum ADB size for views that share a cache.  Use this limit to suppress
 * the total of memory footprint, which should be the main reason for sharing
 * a cache.  Only effective when a finite max-cache-size is specified.
 * This is currently defined to be 8MB.
 */
Mark Andrews's avatar
Mark Andrews committed
217
#define MAX_ADB_SIZE_FOR_CACHESHARE	8388608U
218

219
struct named_dispatch {
220 221 222
	isc_sockaddr_t			addr;
	unsigned int			dispatchgen;
	dns_dispatch_t			*dispatch;
223
	ISC_LINK(struct named_dispatch)	link;
224 225
};

226
struct named_cache {
227 228
	dns_cache_t			*cache;
	dns_view_t			*primaryview;
229 230
	bool			needflush;
	bool			adbsizeadjusted;
231
	dns_rdataclass_t		rdclass;
232
	ISC_LINK(named_cache_t)		link;
233 234
};

235 236
struct dumpcontext {
	isc_mem_t			*mctx;
237 238 239 240 241
	bool			dumpcache;
	bool			dumpzones;
	bool			dumpadb;
	bool			dumpbad;
	bool			dumpfail;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	FILE				*fp;
	ISC_LIST(struct viewlistentry)	viewlist;
	struct viewlistentry		*view;
	struct zonelistentry		*zone;
	dns_dumpctx_t			*mdctx;
	dns_db_t			*db;
	dns_db_t			*cache;
	isc_task_t			*task;
	dns_dbversion_t			*version;
};

struct viewlistentry {
	dns_view_t			*view;
	ISC_LINK(struct viewlistentry)	link;
	ISC_LIST(struct zonelistentry)	zonelist;
};

struct zonelistentry {
	dns_zone_t			*zone;
	ISC_LINK(struct zonelistentry)	link;
};

264 265
/*%
 * Configuration context to retain for each view that allows
266
 * new zones to be added at runtime.
267
 */
Evan Hunt's avatar
Evan Hunt committed
268
typedef struct ns_cfgctx {
269
	isc_mem_t *			mctx;
270 271
	cfg_parser_t *			conf_parser;
	cfg_parser_t *			add_parser;
272
	cfg_obj_t *			config;
273
	cfg_obj_t *			vconfig;
274
	cfg_obj_t *			nzf_config;
275
	cfg_aclconfctx_t *		actx;
Evan Hunt's avatar
Evan Hunt committed
276
} ns_cfgctx_t;
277

278 279 280 281 282 283
/*%
 * A function to write out added-zone configuration to the new_zone_file
 * specified in 'view'. Maybe called by delete_zoneconf().
 */
typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);

284 285 286 287 288 289
/*%
 * Holds state information for the initial zone loading process.
 * Uses the isc_refcount structure to count the number of views
 * with pending zone loads, dereferencing as each view finishes.
 */
typedef struct {
290
		named_server_t *server;
291
		bool reconfig;
292 293 294
		isc_refcount_t refs;
} ns_zoneload_t;

295
typedef struct {
296
	named_server_t *server;
297 298 299 300 301 302 303 304
} catz_cb_data_t;

typedef struct catz_chgzone_event {
	ISC_EVENT_COMMON(struct catz_chgzone_event);
	dns_catz_entry_t *entry;
	dns_catz_zone_t *origin;
	dns_view_t *view;
	catz_cb_data_t *cbd;
305
	bool mod;
306 307
} catz_chgzone_event_t;

308 309 310
/*
 * These zones should not leak onto the Internet.
 */
311
const char *empty_zones[] = {
312
	/* RFC 1918 */
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
	"10.IN-ADDR.ARPA",
	"16.172.IN-ADDR.ARPA",
	"17.172.IN-ADDR.ARPA",
	"18.172.IN-ADDR.ARPA",
	"19.172.IN-ADDR.ARPA",
	"20.172.IN-ADDR.ARPA",
	"21.172.IN-ADDR.ARPA",
	"22.172.IN-ADDR.ARPA",
	"23.172.IN-ADDR.ARPA",
	"24.172.IN-ADDR.ARPA",
	"25.172.IN-ADDR.ARPA",
	"26.172.IN-ADDR.ARPA",
	"27.172.IN-ADDR.ARPA",
	"28.172.IN-ADDR.ARPA",
	"29.172.IN-ADDR.ARPA",
	"30.172.IN-ADDR.ARPA",
	"31.172.IN-ADDR.ARPA",
	"168.192.IN-ADDR.ARPA",
331

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	/* RFC 6598 */
	"64.100.IN-ADDR.ARPA",
	"65.100.IN-ADDR.ARPA",
	"66.100.IN-ADDR.ARPA",
	"67.100.IN-ADDR.ARPA",
	"68.100.IN-ADDR.ARPA",
	"69.100.IN-ADDR.ARPA",
	"70.100.IN-ADDR.ARPA",
	"71.100.IN-ADDR.ARPA",
	"72.100.IN-ADDR.ARPA",
	"73.100.IN-ADDR.ARPA",
	"74.100.IN-ADDR.ARPA",
	"75.100.IN-ADDR.ARPA",
	"76.100.IN-ADDR.ARPA",
	"77.100.IN-ADDR.ARPA",
	"78.100.IN-ADDR.ARPA",
	"79.100.IN-ADDR.ARPA",
	"80.100.IN-ADDR.ARPA",
	"81.100.IN-ADDR.ARPA",
	"82.100.IN-ADDR.ARPA",
	"83.100.IN-ADDR.ARPA",
	"84.100.IN-ADDR.ARPA",
	"85.100.IN-ADDR.ARPA",
	"86.100.IN-ADDR.ARPA",
	"87.100.IN-ADDR.ARPA",
	"88.100.IN-ADDR.ARPA",
	"89.100.IN-ADDR.ARPA",
	"90.100.IN-ADDR.ARPA",
	"91.100.IN-ADDR.ARPA",
	"92.100.IN-ADDR.ARPA",
	"93.100.IN-ADDR.ARPA",
	"94.100.IN-ADDR.ARPA",
	"95.100.IN-ADDR.ARPA",
	"96.100.IN-ADDR.ARPA",
	"97.100.IN-ADDR.ARPA",
	"98.100.IN-ADDR.ARPA",
	"99.100.IN-ADDR.ARPA",
	"100.100.IN-ADDR.ARPA",
	"101.100.IN-ADDR.ARPA",
	"102.100.IN-ADDR.ARPA",
	"103.100.IN-ADDR.ARPA",
	"104.100.IN-ADDR.ARPA",
	"105.100.IN-ADDR.ARPA",
	"106.100.IN-ADDR.ARPA",
	"107.100.IN-ADDR.ARPA",
	"108.100.IN-ADDR.ARPA",
	"109.100.IN-ADDR.ARPA",
	"110.100.IN-ADDR.ARPA",
	"111.100.IN-ADDR.ARPA",
	"112.100.IN-ADDR.ARPA",
	"113.100.IN-ADDR.ARPA",
	"114.100.IN-ADDR.ARPA",
	"115.100.IN-ADDR.ARPA",
	"116.100.IN-ADDR.ARPA",
	"117.100.IN-ADDR.ARPA",
	"118.100.IN-ADDR.ARPA",
	"119.100.IN-ADDR.ARPA",
	"120.100.IN-ADDR.ARPA",
	"121.100.IN-ADDR.ARPA",
	"122.100.IN-ADDR.ARPA",
	"123.100.IN-ADDR.ARPA",
	"124.100.IN-ADDR.ARPA",
	"125.100.IN-ADDR.ARPA",
	"126.100.IN-ADDR.ARPA",
	"127.100.IN-ADDR.ARPA",

398
	/* RFC 5735 and RFC 5737 */
399 400 401 402 403 404 405
	"0.IN-ADDR.ARPA",	/* THIS NETWORK */
	"127.IN-ADDR.ARPA",	/* LOOPBACK */
	"254.169.IN-ADDR.ARPA",	/* LINK LOCAL */
	"2.0.192.IN-ADDR.ARPA",	/* TEST NET */
	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
	"255.255.255.255.IN-ADDR.ARPA",	/* BROADCAST */
406 407

	/* Local IPv6 Unicast Addresses */
408 409
	"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
	"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
Francis Dupont's avatar
Francis Dupont committed
410
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
411 412 413 414 415
	"D.F.IP6.ARPA",
	"8.E.F.IP6.ARPA",	/* LINK LOCAL */
	"9.E.F.IP6.ARPA",	/* LINK LOCAL */
	"A.E.F.IP6.ARPA",	/* LINK LOCAL */
	"B.E.F.IP6.ARPA",	/* LINK LOCAL */
416

417
	/* Example Prefix, RFC 3849. */
418
	"8.B.D.0.1.0.0.2.IP6.ARPA",
419

420 421 422
	/* RFC 7534 */
	"EMPTY.AS112.ARPA",

423 424 425
	/* RFC 8375 */
	"HOME.ARPA",

426
	NULL
427 428
};

Francis Dupont's avatar
Francis Dupont committed
429 430
ISC_PLATFORM_NORETURN_PRE static void
fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
David Lawrence's avatar
David Lawrence committed
431 432

static void
433
named_server_reload(isc_task_t *task, isc_event_t *event);
434

435
static isc_result_t
436
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
437
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
438
			uint16_t family, ns_listenelt_t **target);
439
static isc_result_t
440
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
441
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
442
			 uint16_t family, ns_listenlist_t **target);
443

444
static isc_result_t
445
configure_forward(const cfg_obj_t *config, dns_view_t *view,
446 447
		  const dns_name_t *origin, const cfg_obj_t *forwarders,
		  const cfg_obj_t *forwardtype);
448

449
static isc_result_t
450 451
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
452

453
static isc_result_t
454 455
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
Evan Hunt's avatar
Evan Hunt committed
456
	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
457 458
	       bool added, bool old_rpz_ok,
	       bool modify);
459

460 461 462 463
static isc_result_t
configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
		   isc_mem_t *mctx, cfg_aclconfctx_t *actx);

464
static isc_result_t
465
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
466

467
static void
468
end_reserved_dispatches(named_server_t *server, bool all);
469

470
static void
471
newzone_cfgctx_destroy(void **cfgp);
472

Mark Andrews's avatar
Mark Andrews committed
473
static inline isc_result_t
474
putstr(isc_buffer_t **b, const char *str);
475

476
static isc_result_t
477 478 479
putmem(isc_buffer_t **b, const char *str, size_t len);

static isc_result_t
480
putuint8(isc_buffer_t **b, uint8_t val);
481

Mark Andrews's avatar
Mark Andrews committed
482
static inline isc_result_t
483
putnull(isc_buffer_t **b);
484

485 486 487 488 489 490 491
static int
count_zones(const cfg_obj_t *conf);

#ifdef HAVE_LMDB
static isc_result_t
migrate_nzf(dns_view_t *view);

492 493 494
static isc_result_t
nzd_writable(dns_view_t *view);

495 496 497
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);

498 499 500 501 502 503
static isc_result_t
nzd_env_reopen(dns_view_t *view);

static void
nzd_env_close(dns_view_t *view);

504
static isc_result_t
505
nzd_close(MDB_txn **txnp, bool commit);
506 507 508 509

static isc_result_t
nzd_count(dns_view_t *view, int *countp);
#else
Evan Hunt's avatar
Evan Hunt committed
510
static isc_result_t
511 512
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
#endif
Evan Hunt's avatar
Evan Hunt committed
513

514
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
515 516
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
517 518
 */
static isc_result_t
519
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
520 521 522
		   const cfg_obj_t *gconfig, const char *aclname,
		   const char *acltuplename, cfg_aclconfctx_t *actx,
		   isc_mem_t *mctx, dns_acl_t **aclp)
523 524
{
	isc_result_t result;
525
	const cfg_obj_t *maps[4];
526
	const cfg_obj_t *aclobj = NULL;
527 528
	int i = 0;

529
	if (*aclp != NULL) {
530
		dns_acl_detach(aclp);
531 532
	}
	if (vconfig != NULL) {
533
		maps[i++] = cfg_tuple_get(vconfig, "options");
534
	}
535
	if (config != NULL) {
536
		const cfg_obj_t *options = NULL;
537
		(void)cfg_map_get(config, "options", &options);
538
		if (options != NULL) {
539
			maps[i++] = options;
540 541 542 543 544 545 546 547
		}
	}
	if (gconfig != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(gconfig, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
		}
548 549
	}
	maps[i] = NULL;
550

551
	(void)named_config_get(maps, aclname, &aclobj);
552
	if (aclobj == NULL) {
553
		/*
554
		 * No value available.	*aclp == NULL.
555
		 */
556
		return (ISC_R_SUCCESS);
557
	}
558

559 560 561 562 563 564 565 566 567
	if (acltuplename != NULL) {
		/*
		 * If the ACL is given in an optional tuple, retrieve it.
		 * The parser should have ensured that a valid object be
		 * returned.
		 */
		aclobj = cfg_tuple_get(aclobj, acltuplename);
	}

568
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
569 570 571 572 573 574 575 576 577 578 579 580
				    actx, mctx, 0, aclp);

	return (result);
}

/*%
 * Configure a sortlist at '*aclp'.  Essentially the same as
 * configure_view_acl() except it calls cfg_acl_fromconfig with a
 * nest_level value of 2.
 */
static isc_result_t
configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
Automatic Updater's avatar
Automatic Updater committed
581 582
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
{
	isc_result_t result;
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
	int i = 0;

	if (*aclp != NULL)
		dns_acl_detach(aclp);
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i] = NULL;

601
	(void)named_config_get(maps, "sortlist", &aclobj);
602 603 604
	if (aclobj == NULL)
		return (ISC_R_SUCCESS);

Automatic Updater's avatar
Automatic Updater committed
605 606 607 608 609 610
	/*
	 * Use a nest level of 3 for the "top level" of the sortlist;
	 * this means each entry in the top three levels will be stored
	 * as lists of separate, nested ACLs, rather than merged together
	 * into IP tables as is usually done with ACLs.
	 */
611
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
612
				    actx, mctx, 3, aclp);
613 614 615 616

	return (result);
}

617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
static isc_result_t
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
			 const char *confname, const char *conftuplename,
			 isc_mem_t *mctx, dns_rbt_t **rbtp)
{
	isc_result_t result;
	const cfg_obj_t *maps[3];
	const cfg_obj_t *obj = NULL;
	const cfg_listelt_t *element;
	int i = 0;
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_buffer_t b;
	const char *str;
	const cfg_obj_t *nameobj;

	if (*rbtp != NULL)
		dns_rbt_destroy(rbtp);
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i] = NULL;

645
	(void)named_config_get(maps, confname, &obj);
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
	if (obj == NULL)
		/*
		 * No value available.	*rbtp == NULL.
		 */
		return (ISC_R_SUCCESS);

	if (conftuplename != NULL) {
		obj = cfg_tuple_get(obj, conftuplename);
		if (cfg_obj_isvoid(obj))
			return (ISC_R_SUCCESS);
	}

	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
	if (result != ISC_R_SUCCESS)
		return (result);

662
	name = dns_fixedname_initname(&fixed);
663 664 665 666 667
	for (element = cfg_list_first(obj);
	     element != NULL;
	     element = cfg_list_next(element)) {
		nameobj = cfg_listelt_value(element);
		str = cfg_obj_asstring(nameobj);
668
		isc_buffer_constinit(&b, str, strlen(str));
669
		isc_buffer_add(&b, strlen(str));
670
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
671 672 673 674 675 676 677
		/*
		 * We don't need the node data, but need to set dummy data to
		 * avoid a partial match with an empty node.  For example, if
		 * we have foo.example.com and bar.example.com, we'd get a match
		 * for baz.example.com, which is not the expected result.
		 * We simply use (void *)1 as the dummy data.
		 */
678 679
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
680
			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
681 682 683 684
				    "failed to add %s for %s: %s",
				    str, confname, isc_result_totext(result));
			goto cleanup;
		}
Automatic Updater's avatar
Automatic Updater committed
685

686 687 688 689 690 691 692
	}

	return (result);

  cleanup:
	dns_rbt_destroy(rbtp);
	return (result);
Automatic Updater's avatar
Automatic Updater committed
693

694 695
}

696
static isc_result_t
697
dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
698
		  bool managed, dst_key_t **target, isc_mem_t *mctx)
699 700
{
	dns_rdataclass_t viewclass;
701
	dns_rdata_dnskey_t keystruct;
702
	uint32_t flags, proto, alg;
703
	const char *keystr, *keynamestr;
704 705 706 707 708 709 710 711 712 713 714
	unsigned char keydata[4096];
	isc_buffer_t keydatabuf;
	unsigned char rrdata[4096];
	isc_buffer_t rrdatabuf;
	isc_region_t r;
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
	isc_buffer_t namebuf;
	isc_result_t result;
	dst_key_t *dstkey = NULL;

715 716
	INSIST(target != NULL && *target == NULL);

717 718 719 720 721 722
	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
	keyname = dns_fixedname_name(&fkeyname);
	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));

Automatic Updater's avatar
Automatic Updater committed
723 724 725 726
	if (managed) {
		const char *initmethod;
		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));

727
		if (strcasecmp(initmethod, "initial-key") != 0) {
728
			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Automatic Updater's avatar
Automatic Updater committed
729 730 731 732 733 734 735
				    "managed key '%s': "
				    "invalid initialization method '%s'",
				    keynamestr, initmethod);
			result = ISC_R_FAILURE;
			goto cleanup;
		}
	}
736

737
	if (vconfig == NULL)
738
		viewclass = dns_rdataclass_in;
739
	else {
740
		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
741
		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
742
					 &viewclass));
743
	}
744
	keystruct.common.rdclass = viewclass;
745
	keystruct.common.rdtype = dns_rdatatype_dnskey;
746
	/*
747
	 * The key data in keystruct is not dynamically allocated.
748 749 750 751 752
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

753
	if (flags > 0xffff)
754
		CHECKM(ISC_R_RANGE, "key flags");
755
	if (proto > 0xff)
756
		CHECKM(ISC_R_RANGE, "key protocol");
757
	if (alg > 0xff)
758
		CHECKM(ISC_R_RANGE, "key algorithm");
759 760 761
	keystruct.flags = (uint16_t)flags;
	keystruct.protocol = (uint8_t)proto;
	keystruct.algorithm = (uint8_t)alg;
762 763 764 765

	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

766
	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
767
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
768 769 770 771
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

772 773 774
	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
	     keystruct.algorithm == DST_ALG_RSAMD5) &&
	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
775
		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
776 777
			    "%s key '%s' has a weak exponent",
			    managed ? "managed" : "trusted",
778 779
			    keynamestr);

780 781 782 783 784
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
785
	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
786
	isc_buffer_add(&namebuf, strlen(keynamestr));
787
	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
788 789 790
	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
			      mctx, &dstkey));

791
	*target = dstkey;
792 793 794
	return (ISC_R_SUCCESS);

 cleanup:
795
	if (result == DST_R_NOCRYPTO) {
796
		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
797 798
			    "ignoring %s key for '%s': no crypto support",
			    managed ? "managed" : "trusted",
799
			    keynamestr);
800
	} else if (result == DST_R_UNSUPPORTEDALG) {
801
		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
802 803 804
			    "skipping %s key for '%s': %s",
			    managed ? "managed" : "trusted",
			    keynamestr, isc_result_totext(result));
805
	} else {
806
		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
807 808
			    "configuring %s key for '%s': %s",
			    managed ? "managed" : "trusted",
809 810 811
			    keynamestr, isc_result_totext(result));
		result = ISC_R_FAILURE;
	}
812 813 814 815 816 817 818

	if (dstkey != NULL)
		dst_key_free(&dstkey);

	return (result);
}

Evan Hunt's avatar
Evan Hunt committed
819 820 821 822 823
/*
 * Load keys from configuration into key table. If 'keyname' is specified,
 * only load keys matching that name. If 'managed' is true, load the key as
 * an initializing key.
 */
824 825
static isc_result_t
load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
826
	       dns_view_t *view, bool managed,
827
	       const dns_name_t *keyname, isc_mem_t *mctx)
828 829
{
	const cfg_listelt_t *elt, *elt2;
830 831
	const cfg_obj_t *key, *keylist;
	dst_key_t *dstkey = NULL;
832 833 834 835
	isc_result_t result;
	dns_keytable_t *secroots = NULL;

	CHECK(dns_view_getsecroots(view, &secroots));
836 837 838

	for (elt = cfg_list_first(keys);
	     elt != NULL;
Evan Hunt's avatar
Evan Hunt committed
839 840
	     elt = cfg_list_next(elt))
	{
841 842 843 844
		keylist = cfg_listelt_value(elt);

		for (elt2 = cfg_list_first(keylist);
		     elt2 != NULL;
Evan Hunt's avatar
Evan Hunt committed
845 846
		     elt2 = cfg_list_next(elt2))
		{
847
			key = cfg_listelt_value(elt2);
848 849 850 851 852 853
			result = dstkey_fromconfig(vconfig, key, managed,
						   &dstkey, mctx);
			if (result ==  DST_R_UNSUPPORTEDALG) {
				result = ISC_R_SUCCESS;
				continue;
			}
Evan Hunt's avatar
Evan Hunt committed
854
			if (result != ISC_R_SUCCESS) {
855
				goto cleanup;
Evan Hunt's avatar
Evan Hunt committed
856
			}
857

858 859 860 861
			/*
			 * If keyname was specified, we only add that key.
			 */
			if (keyname != NULL &&
Automatic Updater's avatar
Automatic Updater committed
862
			    !dns_name_equal(keyname, dst_key_name(dstkey)))
863 864 865 866 867
			{
				dst_key_free(&dstkey);
				continue;
			}

Evan Hunt's avatar
Evan Hunt committed
868 869 870 871 872 873
			/*
			 * This key is taken from the configuration, so
			 * if it's a managed key then it's an
			 * initializing key; that's why 'managed'
			 * is duplicated below.
			 */
874 875
			CHECK(dns_keytable_add(secroots, managed,
					       managed, &dstkey));
876 877 878 879
		}
	}

 cleanup:
Evan Hunt's avatar
Evan Hunt committed
880
	if (dstkey != NULL) {
881
		dst_key_free(&dstkey);
Evan Hunt's avatar
Evan Hunt committed
882 883
	}
	if (secroots != NULL) {
884
		dns_keytable_detach(&secroots);
Evan Hunt's avatar
Evan Hunt committed
885 886
	}
	if (result == DST_R_NOCRYPTO) {
887
		result = ISC_R_SUCCESS;
Evan Hunt's avatar
Evan Hunt committed
888
	}
889
	return (result);
890 891
}

892 893 894
/*%
 * Check whether a key has been successfully loaded.
 */
895
static bool
896 897 898 899 900 901 902
keyloaded(dns_view_t *view, const dns_name_t *name) {
	isc_result_t result;
	dns_keytable_t *secroots = NULL;
	dns_keynode_t *keynode = NULL;

	result = dns_view_getsecroots(view, &secroots);
	if (result != ISC_R_SUCCESS)
903
		return (false);
904 905 906 907 908 909 910 911

	result = dns_keytable_find(secroots, name, &keynode);

	if (keynode != NULL)
		dns_keytable_detachkeynode(secroots, &keynode);
	if (secroots != NULL)
		dns_keytable_detach(&secroots);

912
	return (result == ISC_R_SUCCESS);
913 914
}

915
/*%
916
 * Configure DNSSEC keys for a view.
917
 *
918
 * The per-view configuration values and the server-global defaults are read
919
 * from 'vconfig' and 'config'.
920 921
 */
static isc_result_t
922 923
configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
924
			  bool auto_root, isc_mem_t *mctx)
925
{
926
	isc_result_t result = ISC_R_SUCCESS;
927 928
	const cfg_obj_t *view_keys = NULL;
	const cfg_obj_t *global_keys = NULL;
929
	const cfg_obj_t *view_managed_keys = NULL;
930
	const cfg_obj_t *global_managed_keys = NULL;
931
	const cfg_obj_t *maps[4];
932
	const cfg_obj_t *voptions = NULL;
933
	const cfg_obj_t *options = NULL;
934 935
	const cfg_obj_t *obj = NULL;
	const char *directory;
936
	int i = 0;
937

938
	/* We don't need trust anchors for the _bind view */
939
	if (strcmp(view->name, "_bind") == 0 &&
940 941
	    view->rdclass == dns_rdataclass_chaos)
	{
942 943
		return (ISC_R_SUCCESS);