server.c 413 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 20
#include <sys/stat.h>
#include <sys/types.h>
21
#include <unistd.h>
22

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

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

96 97 98
#include <dst/dst.h>
#include <dst/result.h>

99 100 101
#include <isccfg/grammar.h>
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
102

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

108
#include <bind9/check.h>
109

110
#include <named/config.h>
111
#include <named/control.h>
112
#if defined(HAVE_GEOIP2)
Evan Hunt's avatar
Evan Hunt committed
113
#include <named/geoip.h>
114
#endif /* HAVE_GEOIP2 */
115
#include <named/log.h>
116
#include <named/logconf.h>
117
#include <named/main.h>
118
#include <named/os.h>
Bob Halley's avatar
Bob Halley committed
119
#include <named/server.h>
120
#include <named/statschannel.h>
121 122 123
#include <named/tkeyconf.h>
#include <named/tsigconf.h>
#include <named/zoneconf.h>
124 125
#ifdef HAVE_LIBSCF
#include <stdlib.h>
126 127

#include <named/smf_globals.h>
128
#endif /* ifdef HAVE_LIBSCF */
129 130 131

#ifdef HAVE_LMDB
#include <lmdb.h>
Evan Hunt's avatar
Evan Hunt committed
132
#define count_newzones	   count_newzones_db
133
#define configure_newzones configure_newzones_db
Evan Hunt's avatar
Evan Hunt committed
134
#define dumpzone	   dumpzone_db
135
#else /* HAVE_LMDB */
Evan Hunt's avatar
Evan Hunt committed
136
#define count_newzones	   count_newzones_file
137
#define configure_newzones configure_newzones_file
Evan Hunt's avatar
Evan Hunt committed
138
#define dumpzone	   dumpzone_file
139
#endif /* HAVE_LMDB */
140

141 142
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
143
#endif /* ifndef SIZE_MAX */
144

145 146
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
147
#endif /* ifndef SIZE_AS_PERCENT */
148

149
#ifdef TUNE_LARGE
150 151 152 153 154 155 156
#define RESOLVER_NTASKS_PERCPU 32
#define UDPBUFFERS	       32768
#define EXCLBUFFERS	       32768
#else
#define RESOLVER_NTASKS_PERCPU 8
#define UDPBUFFERS	       1000
#define EXCLBUFFERS	       4096
157 158
#endif /* TUNE_LARGE */

159 160
#define MAX_TCP_TIMEOUT 65535

161
/*%
162 163 164
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
#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;                                          \
		}                                                              \
191 192
	} while (0)

193 194 195 196 197 198 199 200 201 202
#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;                                          \
		}                                                              \
203 204
	} while (0)

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

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

220
struct named_dispatch {
Evan Hunt's avatar
Evan Hunt committed
221 222
	isc_sockaddr_t addr;
	unsigned int dispatchgen;
223 224
	dns_dispatch_t *dispatch;
	ISC_LINK(struct named_dispatch) link;
225 226
};

227
struct named_cache {
Evan Hunt's avatar
Evan Hunt committed
228 229 230 231
	dns_cache_t *cache;
	dns_view_t *primaryview;
	bool needflush;
	bool adbsizeadjusted;
232 233
	dns_rdataclass_t rdclass;
	ISC_LINK(named_cache_t) link;
234 235
};

236
struct dumpcontext {
237
	isc_mem_t *mctx;
Evan Hunt's avatar
Evan Hunt committed
238 239 240 241 242 243
	bool dumpcache;
	bool dumpzones;
	bool dumpadb;
	bool dumpbad;
	bool dumpfail;
	FILE *fp;
244 245 246
	ISC_LIST(struct viewlistentry) viewlist;
	struct viewlistentry *view;
	struct zonelistentry *zone;
Evan Hunt's avatar
Evan Hunt committed
247 248 249 250 251
	dns_dumpctx_t *mdctx;
	dns_db_t *db;
	dns_db_t *cache;
	isc_task_t *task;
	dns_dbversion_t *version;
252 253 254
};

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

struct zonelistentry {
261 262
	dns_zone_t *zone;
	ISC_LINK(struct zonelistentry) link;
263 264
};

265 266
/*%
 * Configuration context to retain for each view that allows
267
 * new zones to be added at runtime.
268
 */
Evan Hunt's avatar
Evan Hunt committed
269
typedef struct ns_cfgctx {
Evan Hunt's avatar
Evan Hunt committed
270 271 272 273 274 275
	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;
276
	cfg_aclconfctx_t *actx;
Evan Hunt's avatar
Evan Hunt committed
277
} ns_cfgctx_t;
278

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

285 286 287 288 289 290
/*%
 * 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 {
291
	named_server_t *server;
Evan Hunt's avatar
Evan Hunt committed
292 293
	bool reconfig;
	isc_refcount_t refs;
294 295
} ns_zoneload_t;

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

typedef struct catz_chgzone_event {
	ISC_EVENT_COMMON(struct catz_chgzone_event);
	dns_catz_entry_t *entry;
Evan Hunt's avatar
Evan Hunt committed
303 304 305 306
	dns_catz_zone_t *origin;
	dns_view_t *view;
	catz_cb_data_t *cbd;
	bool mod;
307 308
} catz_chgzone_event_t;

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

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

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

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

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

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

375 376 377
	/* RFC 7534 */
	"EMPTY.AS112.ARPA",

378 379 380
	/* RFC 8375 */
	"HOME.ARPA",

381
	NULL
382 383
};

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

Ondřej Surý's avatar
Ondřej Surý committed
388 389
static void
named_server_reload(isc_task_t *task, isc_event_t *event);
390

Ondřej Surý's avatar
Ondřej Surý committed
391 392 393 394 395 396 397 398
static isc_result_t
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			uint16_t family, ns_listenelt_t **target);
static isc_result_t
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			 uint16_t family, ns_listenlist_t **target);
399

Ondřej Surý's avatar
Ondřej Surý committed
400 401 402 403
static isc_result_t
configure_forward(const cfg_obj_t *config, dns_view_t *view,
		  const dns_name_t *origin, const cfg_obj_t *forwarders,
		  const cfg_obj_t *forwardtype);
404

Ondřej Surý's avatar
Ondřej Surý committed
405 406 407
static isc_result_t
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
408

Ondřej Surý's avatar
Ondřej Surý committed
409 410 411 412 413 414
static isc_result_t
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,
	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
	       bool modify);
415

Ondřej Surý's avatar
Ondřej Surý committed
416 417 418
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);
419

Ondřej Surý's avatar
Ondřej Surý committed
420 421
static isc_result_t
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
422

Ondřej Surý's avatar
Ondřej Surý committed
423 424
static void
end_reserved_dispatches(named_server_t *server, bool all);
425

Ondřej Surý's avatar
Ondřej Surý committed
426 427
static void
newzone_cfgctx_destroy(void **cfgp);
428

Ondřej Surý's avatar
Ondřej Surý committed
429 430
static inline isc_result_t
putstr(isc_buffer_t **b, const char *str);
431

Ondřej Surý's avatar
Ondřej Surý committed
432 433
static isc_result_t
putmem(isc_buffer_t **b, const char *str, size_t len);
434

Ondřej Surý's avatar
Ondřej Surý committed
435 436
static isc_result_t
putuint8(isc_buffer_t **b, uint8_t val);
437

Ondřej Surý's avatar
Ondřej Surý committed
438 439
static inline isc_result_t
putnull(isc_buffer_t **b);
440

Ondřej Surý's avatar
Ondřej Surý committed
441 442
static int
count_zones(const cfg_obj_t *conf);
443 444

#ifdef HAVE_LMDB
Ondřej Surý's avatar
Ondřej Surý committed
445 446
static isc_result_t
migrate_nzf(dns_view_t *view);
447

Ondřej Surý's avatar
Ondřej Surý committed
448 449
static isc_result_t
nzd_writable(dns_view_t *view);
450

Ondřej Surý's avatar
Ondřej Surý committed
451 452
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
453

Ondřej Surý's avatar
Ondřej Surý committed
454 455
static isc_result_t
nzd_env_reopen(dns_view_t *view);
456

Ondřej Surý's avatar
Ondřej Surý committed
457 458
static void
nzd_env_close(dns_view_t *view);
459

Ondřej Surý's avatar
Ondřej Surý committed
460 461
static isc_result_t
nzd_close(MDB_txn **txnp, bool commit);
462

Ondřej Surý's avatar
Ondřej Surý committed
463 464
static isc_result_t
nzd_count(dns_view_t *view, int *countp);
465
#else  /* ifdef HAVE_LMDB */
Ondřej Surý's avatar
Ondřej Surý committed
466 467
static isc_result_t
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
468
#endif /* ifdef HAVE_LMDB */
Evan Hunt's avatar
Evan Hunt committed
469

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

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

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

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

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

	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
536
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
Evan Hunt's avatar
Evan Hunt committed
537 538
			dns_acl_t **aclp) {
	isc_result_t result;
539 540
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
Evan Hunt's avatar
Evan Hunt committed
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
static isc_result_t
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
			 const char *confname, const char *conftuplename,
Evan Hunt's avatar
Evan Hunt committed
578 579 580 581
			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
	isc_result_t result;
	const cfg_obj_t *maps[3];
	const cfg_obj_t *obj = NULL;
582
	const cfg_listelt_t *element;
Evan Hunt's avatar
Evan Hunt committed
583 584 585 586 587 588
	int i = 0;
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_buffer_t b;
	const char *str;
	const cfg_obj_t *nameobj;
589

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

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

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

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

625
	name = dns_fixedname_initname(&fixed);
626
	for (element = cfg_list_first(obj); element != NULL;
Evan Hunt's avatar
Evan Hunt committed
627 628
	     element = cfg_list_next(element))
	{
629 630
		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
ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
Evan Hunt's avatar
Evan Hunt committed
659 660
	      unsigned char *digest, dns_rdata_ds_t *ds) {
	isc_result_t result;
661
	dns_rdata_dnskey_t keystruct;
Evan Hunt's avatar
Evan Hunt committed
662 663 664 665 666 667 668 669 670 671 672 673
	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;
674 675 676 677 678
	enum { INIT_DNSKEY,
	       STATIC_DNSKEY,
	       INIT_DS,
	       STATIC_DS,
	       TRUSTED } anchortype;
679

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

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

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

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

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

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

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

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

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

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

	ISC_LINK_INIT(&ds->common, link);

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

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

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

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

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

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

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

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

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

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

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

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

		break;
836 837 838 839 840

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

	return (ISC_R_SUCCESS);

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

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

	switch (result) {
	case ISC_R_SUCCESS:
		/*
877
		 * Trust anchor was parsed correctly.
878
		 */
879 880 881 882 883 884
		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);
885
		}
Michał Kępień's avatar