server.c 410 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
#include <ctype.h>
15
#include <inttypes.h>
16
#include <limits.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
#include <unistd.h>
20

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

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

94 95 96
#include <isccfg/grammar.h>
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
97

98
#include <ns/client.h>
99
#include <ns/hooks.h>
100
#include <ns/interfacemgr.h>
101
#include <ns/listenlist.h>
102

103 104 105
#include <bind9/check.h>
#include <dst/dst.h>
#include <dst/result.h>
106
#include <named/config.h>
107
#include <named/control.h>
108 109
#include <sys/stat.h>
#include <sys/types.h>
110
#if defined(HAVE_GEOIP2)
Evan Hunt's avatar
Evan Hunt committed
111
#include <named/geoip.h>
112
#endif /* HAVE_GEOIP2 */
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 123
#ifdef HAVE_LIBSCF
#include <stdlib.h>
124 125

#include <named/smf_globals.h>
126
#endif
127 128 129 130 131 132

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

139 140 141 142
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif

143 144 145 146
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
#endif

147 148 149 150 151 152 153 154 155 156
#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 */

157 158
#define MAX_TCP_TIMEOUT 65535

159
/*%
160 161 162
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
#define CHECK(op)                            \
	do {                                 \
		result = (op);               \
		if (result != ISC_R_SUCCESS) \
			goto cleanup;        \
	} while (0)

#define TCHECK(op)                               \
	do {                                     \
		tresult = (op);                  \
		if (tresult != ISC_R_SUCCESS) {  \
			isc_buffer_clear(*text); \
			goto cleanup;            \
		}                                \
	} while (0)

#define CHECKM(op, msg)                                                        \
	do {                                                                   \
		result = (op);                                                 \
		if (result != ISC_R_SUCCESS) {                                 \
			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
				      "%s: %s", msg,                           \
				      isc_result_totext(result));              \
			goto cleanup;                                          \
		}                                                              \
189 190
	} while (0)

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

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

210 211 212 213 214 215
/*%
 * 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.
 */
216
#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
217

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

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

234
struct dumpcontext {
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	isc_mem_t *mctx;
	bool	   dumpcache;
	bool	   dumpzones;
	bool	   dumpadb;
	bool	   dumpbad;
	bool	   dumpfail;
	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;
250 251 252
};

struct viewlistentry {
253 254 255
	dns_view_t *view;
	ISC_LINK(struct viewlistentry) link;
	ISC_LIST(struct zonelistentry) zonelist;
256 257 258
};

struct zonelistentry {
259 260
	dns_zone_t *zone;
	ISC_LINK(struct zonelistentry) link;
261 262
};

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

277 278 279 280 281 282
/*%
 * 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);

283 284 285 286 287 288
/*%
 * 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 {
289 290 291
	named_server_t *server;
	bool		reconfig;
	isc_refcount_t	refs;
292 293
} ns_zoneload_t;

294
typedef struct {
295
	named_server_t *server;
296 297 298 299 300
} catz_cb_data_t;

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

Mark Andrews's avatar
Mark Andrews committed
307 308
typedef struct {
	unsigned int magic;
309
#define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
Mark Andrews's avatar
Mark Andrews committed
310
	isc_buffer_t **text;
311
	isc_result_t   result;
Mark Andrews's avatar
Mark Andrews committed
312 313
} ns_dzarg_t;

314 315 316
/*
 * These zones should not leak onto the Internet.
 */
317
const char *empty_zones[] = {
318
	/* RFC 1918 */
319 320 321 322 323 324
	"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",
325

326
	/* RFC 6598 */
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
	"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",
348 349
	"127.100.IN-ADDR.ARPA",

350
	/* RFC 5735 and RFC 5737 */
351 352 353 354
	"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 */
355 356
	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
357
	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
358 359

	/* Local IPv6 Unicast Addresses */
360 361 362 363
	"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
364
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
365 366 367 368
	"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 */
369

370
	/* Example Prefix, RFC 3849. */
371
	"8.B.D.0.1.0.0.2.IP6.ARPA",
372

373 374 375
	/* RFC 7534 */
	"EMPTY.AS112.ARPA",

376 377 378
	/* RFC 8375 */
	"HOME.ARPA",

379
	NULL
380 381
};

Francis Dupont's avatar
Francis Dupont committed
382
ISC_PLATFORM_NORETURN_PRE static void
383 384
fatal(named_server_t *server, const char *msg,
      isc_result_t result) ISC_PLATFORM_NORETURN_POST;
David Lawrence's avatar
David Lawrence committed
385 386

static void
387
named_server_reload(isc_task_t *task, isc_event_t *event);
388

389
static isc_result_t
390
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
391
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
392
			uint16_t family, ns_listenelt_t **target);
393
static isc_result_t
394
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
395
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
396
			 uint16_t family, ns_listenlist_t **target);
397

398
static isc_result_t
399
configure_forward(const cfg_obj_t *config, dns_view_t *view,
400 401
		  const dns_name_t *origin, const cfg_obj_t *forwarders,
		  const cfg_obj_t *forwardtype);
402

403
static isc_result_t
404 405
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
406

407
static isc_result_t
408 409
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,
410
	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
411
	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
412
	       bool modify);
413

414 415 416 417
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);

418
static isc_result_t
419
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
420

421
static void
422
end_reserved_dispatches(named_server_t *server, bool all);
423

424
static void
425
newzone_cfgctx_destroy(void **cfgp);
426

Mark Andrews's avatar
Mark Andrews committed
427
static inline isc_result_t
428
putstr(isc_buffer_t **b, const char *str);
429

430
static isc_result_t
431 432 433
putmem(isc_buffer_t **b, const char *str, size_t len);

static isc_result_t
434
putuint8(isc_buffer_t **b, uint8_t val);
435

Mark Andrews's avatar
Mark Andrews committed
436
static inline isc_result_t
437
putnull(isc_buffer_t **b);
438

439 440 441 442 443 444 445
static int
count_zones(const cfg_obj_t *conf);

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

446 447 448
static isc_result_t
nzd_writable(dns_view_t *view);

449 450 451
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);

452 453 454 455 456 457
static isc_result_t
nzd_env_reopen(dns_view_t *view);

static void
nzd_env_close(dns_view_t *view);

458
static isc_result_t
459
nzd_close(MDB_txn **txnp, bool commit);
460 461 462 463

static isc_result_t
nzd_count(dns_view_t *view, int *countp);
#else
Evan Hunt's avatar
Evan Hunt committed
464
static isc_result_t
465 466
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
#endif
Evan Hunt's avatar
Evan Hunt committed
467

468
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
469 470
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
471 472
 */
static isc_result_t
473
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
474 475 476
		   const cfg_obj_t *gconfig, const char *aclname,
		   const char *acltuplename, cfg_aclconfctx_t *actx,
		   isc_mem_t *mctx, dns_acl_t **aclp)
477
{
478
	isc_result_t	 result;
479
	const cfg_obj_t *maps[4];
480
	const cfg_obj_t *aclobj = NULL;
481
	int		 i = 0;
482

483
	if (*aclp != NULL) {
484
		dns_acl_detach(aclp);
485 486
	}
	if (vconfig != NULL) {
487
		maps[i++] = cfg_tuple_get(vconfig, "options");
488
	}
489
	if (config != NULL) {
490
		const cfg_obj_t *options = NULL;
491
		(void)cfg_map_get(config, "options", &options);
492
		if (options != NULL) {
493
			maps[i++] = options;
494 495 496 497 498 499 500 501
		}
	}
	if (gconfig != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(gconfig, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
		}
502 503
	}
	maps[i] = NULL;
504

505
	(void)named_config_get(maps, aclname, &aclobj);
506
	if (aclobj == NULL) {
507
		/*
508
		 * No value available.	*aclp == NULL.
509
		 */
510
		return (ISC_R_SUCCESS);
511
	}
512

513 514 515 516 517 518 519 520 521
	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);
	}

522 523
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
				    aclp);
524 525 526 527 528 529 530 531 532 533 534

	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
535 536
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
537
{
538
	isc_result_t	 result;
539 540
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
541
	int		 i = 0;
542 543 544 545 546 547 548 549 550 551 552 553 554

	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;

555
	(void)named_config_get(maps, "sortlist", &aclobj);
556 557 558
	if (aclobj == NULL)
		return (ISC_R_SUCCESS);

Automatic Updater's avatar
Automatic Updater committed
559 560 561 562 563 564
	/*
	 * 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.
	 */
565 566
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
				    aclp);
567 568 569 570

	return (result);
}

571 572 573 574 575
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)
{
576 577 578
	isc_result_t	     result;
	const cfg_obj_t *    maps[3];
	const cfg_obj_t *    obj = NULL;
579
	const cfg_listelt_t *element;
580 581 582 583 584 585
	int		     i = 0;
	dns_fixedname_t	     fixed;
	dns_name_t *	     name;
	isc_buffer_t	     b;
	const char *	     str;
	const cfg_obj_t *    nameobj;
586 587 588 589 590 591 592 593 594 595 596 597 598

	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;

599
	(void)named_config_get(maps, confname, &obj);
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
	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);

616
	name = dns_fixedname_initname(&fixed);
617
	for (element = cfg_list_first(obj); element != NULL;
618 619 620
	     element = cfg_list_next(element)) {
		nameobj = cfg_listelt_value(element);
		str = cfg_obj_asstring(nameobj);
621
		isc_buffer_constinit(&b, str, strlen(str));
622
		isc_buffer_add(&b, strlen(str));
623
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
624 625 626 627 628 629 630
		/*
		 * 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.
		 */
631 632
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
633
			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
634 635
				    "failed to add %s for %s: %s", str,
				    confname, isc_result_totext(result));
636 637
			goto cleanup;
		}
638 639 640 641
	}

	return (result);

642
cleanup:
643 644 645 646
	dns_rbt_destroy(rbtp);
	return (result);
}

647
static isc_result_t
648 649
ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
	      unsigned char *digest, dns_rdata_ds_t *ds)
650
{
651
	isc_result_t	   result;
652
	dns_rdata_dnskey_t keystruct;
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
	dns_rdata_t	   rdata = DNS_RDATA_INIT;
	uint32_t	   rdata1, rdata2, rdata3;
	const char *	   datastr = NULL, *namestr = NULL;
	unsigned char	   data[4096];
	isc_buffer_t	   databuf;
	unsigned char	   rrdata[4096];
	isc_buffer_t	   rrdatabuf;
	isc_region_t	   r;
	dns_fixedname_t	   fname;
	dns_name_t *	   name = NULL;
	isc_buffer_t	   namebuf;
	const char *	   atstr = NULL;
	enum { INIT_DNSKEY,
	       STATIC_DNSKEY,
	       INIT_DS,
	       STATIC_DS,
	       TRUSTED } anchortype;
670

671
	REQUIRE(namestrp != NULL && *namestrp == NULL);
672
	REQUIRE(ds != NULL);
673 674

	/* if DNSKEY, flags; if DS, key tag */
675
	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
676 677

	/* if DNSKEY, protocol; if DS, algorithm */
678
	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
679 680

	/* if DNSKEY, algorithm; if DS, digest type */
681
	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
682

683 684
	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
	*namestrp = namestr;
685

686 687 688 689
	name = dns_fixedname_initname(&fname);
	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
	isc_buffer_add(&namebuf, strlen(namestr));
	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
690

Evan Hunt's avatar
Evan Hunt committed
691
	if (*initialp) {
692
		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
Automatic Updater's avatar
Automatic Updater committed
693

694 695 696 697
		if (strcasecmp(atstr, "static-key") == 0) {
			*initialp = false;
			anchortype = STATIC_DNSKEY;
		} else if (strcasecmp(atstr, "static-ds") == 0) {
Evan Hunt's avatar
Evan Hunt committed
698
			*initialp = false;
699 700 701 702 703 704
			anchortype = STATIC_DS;
		} else if (strcasecmp(atstr, "initial-key") == 0) {
			anchortype = INIT_DNSKEY;
		} else if (strcasecmp(atstr, "initial-ds") == 0) {
			anchortype = INIT_DS;
		} else {
705
			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
706
				    "key '%s': "
Automatic Updater's avatar
Automatic Updater committed
707
				    "invalid initialization method '%s'",
708
				    namestr, atstr);
Automatic Updater's avatar
Automatic Updater committed
709 710 711
			result = ISC_R_FAILURE;
			goto cleanup;
		}
712 713
	} else {
		anchortype = TRUSTED;
Automatic Updater's avatar
Automatic Updater committed
714
	}
715

716 717 718
	isc_buffer_init(&databuf, data, sizeof(data));
	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

719 720
	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
				.common.rdtype = dns_rdatatype_ds };
721 722 723

	ISC_LINK_INIT(&ds->common, link);

724
	switch (anchortype) {
725 726 727 728 729 730 731 732 733
	case INIT_DNSKEY:
	case STATIC_DNSKEY:
	case TRUSTED:
		/*
		 * This function should never be reached for view
		 * class other than IN
		 */
		keystruct.common.rdclass = dns_rdataclass_in;
		keystruct.common.rdtype = dns_rdatatype_dnskey;
Evan Hunt's avatar
Evan Hunt committed
734

735 736 737 738
		/*
		 * The key data in keystruct is not dynamically allocated.
		 */
		keystruct.mctx = NULL;
739

740 741
		ISC_LINK_INIT(&keystruct.common, link);

742
		if (rdata1 > 0xffff) {
743 744
			CHECKM(ISC_R_RANGE, "key flags");
		}
745
		if (rdata1 & DNS_KEYFLAG_REVOKE) {
746 747
			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
		}
748
		if (rdata2 > 0xff) {
749 750
			CHECKM(ISC_R_RANGE, "key protocol");
		}
751
		if (rdata3 > 0xff) {
752 753 754
			CHECKM(ISC_R_RANGE, "key algorithm");
		}

755 756 757
		keystruct.flags = (uint16_t)rdata1;
		keystruct.protocol = (uint8_t)rdata2;
		keystruct.algorithm = (uint8_t)rdata3;
758

759 760 761 762
		if (!dst_algorithm_supported(keystruct.algorithm)) {
			CHECK(DST_R_UNSUPPORTEDALG);
		}

763 764 765 766 767 768
		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
		CHECK(isc_base64_decodestring(datastr, &databuf));
		isc_buffer_usedregion(&databuf, &r);
		keystruct.datalen = r.length;
		keystruct.data = r.base;

769
		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
770 771
					   keystruct.common.rdtype, &keystruct,
					   &rrdatabuf));
772 773
		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
					  digest, ds));
774 775 776 777
		break;

	case INIT_DS:
	case STATIC_DS:
778
		if (rdata1 > 0xffff) {
779 780
			CHECKM(ISC_R_RANGE, "key tag");
		}
781
		if (rdata2 > 0xff) {
782 783
			CHECKM(ISC_R_RANGE, "key algorithm");
		}
784
		if (rdata3 > 0xff) {
785 786 787
			CHECKM(ISC_R_RANGE, "digest type");
		}

788 789 790
		ds->key_tag = (uint16_t)rdata1;
		ds->algorithm = (uint8_t)rdata2;
		ds->digest_type = (uint8_t)rdata3;
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811

		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
		CHECK(isc_hex_decodestring(datastr, &databuf));
		isc_buffer_usedregion(&databuf, &r);

		switch (ds->digest_type) {
		case DNS_DSDIGEST_SHA1:
			if (r.length != ISC_SHA1_DIGESTLENGTH) {
				CHECK(ISC_R_UNEXPECTEDEND);
			}
			break;
		case DNS_DSDIGEST_SHA256:
			if (r.length != ISC_SHA256_DIGESTLENGTH) {
				CHECK(ISC_R_UNEXPECTEDEND);
			}
			break;
		case DNS_DSDIGEST_SHA384:
			if (r.length != ISC_SHA384_DIGESTLENGTH) {
				CHECK(ISC_R_UNEXPECTEDEND);
			}
			break;
812 813 814 815 816 817 818 819
		default:
			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
				    "key '%s': "
				    "unknown ds digest type %u",
				    namestr, ds->digest_type);
			result = ISC_R_FAILURE;
			goto cleanup;
			break;
820 821 822
		}

		ds->length = r.length;
823
		ds->digest = digest;
824 825 826
		memmove(ds->digest, r.base, r.length);

		break;
827 828 829 830 831

	default:
		INSIST(0);
		ISC_UNREACHABLE();
	}
832 833 834

	return (ISC_R_SUCCESS);

835
cleanup:
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
	return (result);
}

/*%
 * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
 * add the key to 'secroots' if both of the following conditions are true:
 *
 *   - 'keyname_match' is NULL or it matches the owner name of 'key',
 *   - support for the algorithm used by 'key' is not disabled by 'resolver'
 *     for the owner name of 'key'.
 *
 * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
 * the memory context to use for allocating memory.
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
851 852
process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
	    const dns_name_t *keyname_match, dns_resolver_t *resolver,
853
	    bool managed)
854
{
855
	dns_fixedname_t fkeyname;
856 857 858 859 860 861 862
	dns_name_t *	keyname = NULL;
	const char *	namestr = NULL;
	dns_rdata_ds_t	ds;
	isc_result_t	result;
	bool		initializing = managed;
	unsigned char	digest[ISC_MAX_MD_SIZE];
	isc_buffer_t	b;
863

864
	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
865 866 867 868

	switch (result) {
	case ISC_R_SUCCESS:
		/*
869
		 * Trust anchor was parsed correctly.
870
		 */
871 872 873 874 875 876
		isc_buffer_constinit(&b, namestr, strlen(namestr));
		isc_buffer_add(&b, strlen(namestr));
		keyname = dns_fixedname_initname(&fkeyname);
		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
		if (result != ISC_R_SUCCESS) {
			return (result);
877
		}
878 879 880 881 882 883 884 885 886
		break;
	case DST_R_UNSUPPORTEDALG:
	case DST_R_BADKEYTYPE:
		/*
		 * Key was parsed correctly, but it cannot be used; this is not
		 * a fatal error - log a warning about this key being ignored,
		 * but do not prevent any further ones from being processed.
		 */
		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
Evan Hunt's avatar
Evan Hunt committed
887 888
			    "ignoring %s for '%s': %s",
			    initializing ? "initial-key" : "static-key",
889
			    namestr, isc_result_totext(result));
890 891 892 893 894
		return (ISC_R_SUCCESS);
	case DST_R_NOCRYPTO:
		/*
		 * Crypto support is not available.
		 */
895
		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
896 897
			    "ignoring %s for '%s': no crypto support",
			    initializing ? "initial-key" : "static-key",
898
			    namestr);
899 900 901 902 903 904 905
		return (result);
	default:
		/*
		 * Something unexpected happened; we have no choice but to
		 * indicate an error so that the configuration loading process
		 * is interrupted.
		 */
906
		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
907 908
			    "configuring %s for '%s': %s",
			    initializing ? "initial-key" : "static-key",
909
			    namestr, isc_result_totext(result));
910
		return (ISC_R_FAILURE);
911
	}
912

913 914 915 916 917 918 919 920 921 922 923 924 925 926
	/*
	 * If the caller requested to only load keys for a specific name and
	 * the owner name of this key does not match the requested name, do not
	 * load it.
	 */
	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
		goto done;
	}

	/*
	 * Ensure that 'resolver' allows using the algorithm of this key for
	 * its owner name.  If it does not, do not load the key and log a
	 * warning, but do not prevent further keys from being processed.
	 */
927 928
	if (!dns_resolver_algorithm_supported(resolver, keyname,
					      ds.algorithm)) {
929
		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
Evan Hunt's avatar
Evan Hunt committed
930 931
			    "ignoring %s for '%s': algorithm is disabled",
			    initializing ? "initial-key" : "static-key",
932
			    namestr);
933 934 935 936
		goto done;
	}

	/*
937
	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
938
	 * "managed-keys" statement may be either static or initializing
Evan Hunt's avatar
Evan Hunt committed
939 940 941
	 * keys. If it's not initializing, we don't want to treat it as
	 * managed, so we use 'initializing' twice here, for both the
	 * 'managed' and 'initializing' arguments to dns_keytable_add().
942
	 */
943 944
	result = dns_keytable_add(secroots, initializing, initializing, keyname,
				  &ds);
945

946
done:
947 948 949
	return (result);
}