server.c 414 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 /* ifdef HAVE_LIBSCF */
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
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
141
#endif /* ifndef SIZE_MAX */
142

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

147 148 149 150
#ifdef TUNE_LARGE
#define RESOLVER_NTASKS 523
#define UDPBUFFERS 32768
#define EXCLBUFFERS 32768
151
#else /* ifdef TUNE_LARGE */
152 153 154 155 156
#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

static isc_result_t
nzd_count(dns_view_t *view, int *countp);
463
#else  /* ifdef HAVE_LMDB */
Evan Hunt's avatar
Evan Hunt committed
464
static isc_result_t
465
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
466
#endif /* ifdef HAVE_LMDB */
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
	if (*aclp != NULL) {
544
		dns_acl_detach(aclp);
545 546
	}
	if (vconfig != NULL) {
547
		maps[i++] = cfg_tuple_get(vconfig, "options");
548
	}
549 550 551
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
552
		if (options != NULL) {
553
			maps[i++] = options;
554
		}
555 556 557
	}
	maps[i] = NULL;

558
	(void)named_config_get(maps, "sortlist", &aclobj);
559
	if (aclobj == NULL) {
560
		return (ISC_R_SUCCESS);
561
	}
562

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

	return (result);
}

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

591
	if (*rbtp != NULL) {
592
		dns_rbt_destroy(rbtp);
593 594
	}
	if (vconfig != NULL) {
595
		maps[i++] = cfg_tuple_get(vconfig, "options");
596
	}
597 598 599
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
600
		if (options != NULL) {
601
			maps[i++] = options;
602
		}
603 604 605
	}
	maps[i] = NULL;

606
	(void)named_config_get(maps, confname, &obj);
607
	if (obj == NULL) {
608 609 610 611
		/*
		 * No value available.	*rbtp == NULL.
		 */
		return (ISC_R_SUCCESS);
612
	}
613 614 615

	if (conftuplename != NULL) {
		obj = cfg_tuple_get(obj, conftuplename);
616
		if (cfg_obj_isvoid(obj)) {
617
			return (ISC_R_SUCCESS);
618
		}
619 620 621
	}

	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
622
	if (result != ISC_R_SUCCESS) {
623
		return (result);
624
	}
625

626
	name = dns_fixedname_initname(&fixed);
627
	for (element = cfg_list_first(obj); element != NULL;
628 629 630
	     element = cfg_list_next(element)) {
		nameobj = cfg_listelt_value(element);
		str = cfg_obj_asstring(nameobj);
631
		isc_buffer_constinit(&b, str, strlen(str));
632
		isc_buffer_add(&b, strlen(str));
633
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
634 635 636 637 638 639 640
		/*
		 * 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.
		 */
641 642
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
643
			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
644 645
				    "failed to add %s for %s: %s", str,
				    confname, isc_result_totext(result));
646 647
			goto cleanup;
		}
648 649 650 651
	}

	return (result);

652
cleanup:
653 654 655 656
	dns_rbt_destroy(rbtp);
	return (result);
}

657
static isc_result_t
658 659
ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
	      unsigned char *digest, dns_rdata_ds_t *ds)
660
{
661
	isc_result_t	   result;
662
	dns_rdata_dnskey_t keystruct;
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
	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;
680

681
	REQUIRE(namestrp != NULL && *namestrp == NULL);
682
	REQUIRE(ds != NULL);
683 684

	/* if DNSKEY, flags; if DS, key tag */
685
	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
686 687

	/* if DNSKEY, protocol; if DS, algorithm */
688
	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
689 690

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

693 694
	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
	*namestrp = namestr;
695

696 697 698 699
	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));
700

Evan Hunt's avatar
Evan Hunt committed
701
	if (*initialp) {
702
		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
Automatic Updater's avatar
Automatic Updater committed
703

704 705 706 707
		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
708
			*initialp = false;
709 710 711 712 713 714
			anchortype = STATIC_DS;
		} else if (strcasecmp(atstr, "initial-key") == 0) {
			anchortype = INIT_DNSKEY;
		} else if (strcasecmp(atstr, "initial-ds") == 0) {
			anchortype = INIT_DS;
		} else {
715
			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
716
				    "key '%s': "
Automatic Updater's avatar
Automatic Updater committed
717
				    "invalid initialization method '%s'",
718
				    namestr, atstr);
Automatic Updater's avatar
Automatic Updater committed
719 720 721
			result = ISC_R_FAILURE;
			goto cleanup;
		}
722 723
	} else {
		anchortype = TRUSTED;
Automatic Updater's avatar
Automatic Updater committed
724
	}
725

726 727 728
	isc_buffer_init(&databuf, data, sizeof(data));
	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

729 730
	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
				.common.rdtype = dns_rdatatype_ds };
731 732 733

	ISC_LINK_INIT(&ds->common, link);

734
	switch (anchortype) {
735 736 737 738 739 740 741 742 743
	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
744

745 746 747 748
		/*
		 * The key data in keystruct is not dynamically allocated.
		 */
		keystruct.mctx = NULL;
749

750 751
		ISC_LINK_INIT(&keystruct.common, link);

752
		if (rdata1 > 0xffff) {
753 754
			CHECKM(ISC_R_RANGE, "key flags");
		}
755
		if (rdata1 & DNS_KEYFLAG_REVOKE) {
756 757
			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
		}
758
		if (rdata2 > 0xff) {
759 760
			CHECKM(ISC_R_RANGE, "key protocol");
		}
761
		if (rdata3 > 0xff) {
762 763 764
			CHECKM(ISC_R_RANGE, "key algorithm");
		}

765 766 767
		keystruct.flags = (uint16_t)rdata1;
		keystruct.protocol = (uint8_t)rdata2;
		keystruct.algorithm = (uint8_t)rdata3;
768

769 770 771 772
		if (!dst_algorithm_supported(keystruct.algorithm)) {
			CHECK(DST_R_UNSUPPORTEDALG);
		}

773 774 775 776 777 778
		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;

779
		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
780 781
					   keystruct.common.rdtype, &keystruct,
					   &rrdatabuf));
782 783
		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
					  digest, ds));
784 785 786 787
		break;

	case INIT_DS:
	case STATIC_DS:
788
		if (rdata1 > 0xffff) {
789 790
			CHECKM(ISC_R_RANGE, "key tag");
		}
791
		if (rdata2 > 0xff) {
792 793
			CHECKM(ISC_R_RANGE, "key algorithm");
		}
794
		if (rdata3 > 0xff) {
795 796 797
			CHECKM(ISC_R_RANGE, "digest type");
		}

798 799 800
		ds->key_tag = (uint16_t)rdata1;
		ds->algorithm = (uint8_t)rdata2;
		ds->digest_type = (uint8_t)rdata3;
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821

		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;
822 823 824 825 826 827 828 829
		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;
830 831 832
		}

		ds->length = r.length;
833
		ds->digest = digest;
834 835 836
		memmove(ds->digest, r.base, r.length);

		break;
837 838 839 840 841

	default:
		INSIST(0);
		ISC_UNREACHABLE();
	}
842 843 844

	return (ISC_R_SUCCESS);

845
cleanup:
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
	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
861 862
process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
	    const dns_name_t *keyname_match, dns_resolver_t *resolver,
863
	    bool managed)
864
{
865
	dns_fixedname_t fkeyname;
866 867 868 869 870 871 872
	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;
873

874
	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
875 876 877 878

	switch (result) {
	case ISC_R_SUCCESS:
		/*
879
		 * Trust anchor was parsed correctly.
880
		 */
881 882 883 884 885 886
		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);