server.c 423 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
5
 * 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
6
 * file, you can obtain one at https://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
24
25
26
#ifdef HAVE_DNSTAP
#include <fstrm.h>
#endif

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

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

104
105
106
#include <dst/dst.h>
#include <dst/result.h>

107
108
109
#include <isccfg/grammar.h>
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
110

111
#include <ns/client.h>
112
#include <ns/hooks.h>
113
#include <ns/interfacemgr.h>
114
#include <ns/listenlist.h>
115

116
#include <bind9/check.h>
117

118
#include <named/config.h>
119
#include <named/control.h>
120
#if defined(HAVE_GEOIP2)
Evan Hunt's avatar
Evan Hunt committed
121
#include <named/geoip.h>
122
#endif /* HAVE_GEOIP2 */
123
#include <named/log.h>
124
#include <named/logconf.h>
125
#include <named/main.h>
126
#include <named/os.h>
Bob Halley's avatar
Bob Halley committed
127
#include <named/server.h>
128
#include <named/statschannel.h>
129
130
131
#include <named/tkeyconf.h>
#include <named/tsigconf.h>
#include <named/zoneconf.h>
132
133
#ifdef HAVE_LIBSCF
#include <stdlib.h>
134
135

#include <named/smf_globals.h>
136
#endif /* ifdef HAVE_LIBSCF */
137
138

#ifdef HAVE_LMDB
139
140
#include <lmdb.h>

141
#include <dns/lmdb.h>
142
#define count_newzones	   count_newzones_db
143
#define configure_newzones configure_newzones_db
144
#define dumpzone	   dumpzone_db
145
#else /* HAVE_LMDB */
146
#define count_newzones	   count_newzones_file
147
#define configure_newzones configure_newzones_file
148
#define dumpzone	   dumpzone_file
149
#endif /* HAVE_LMDB */
150

151
152
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
153
#endif /* ifndef SIZE_MAX */
154

155
156
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
157
#endif /* ifndef SIZE_AS_PERCENT */
158

159
#ifdef TUNE_LARGE
160
161
162
163
164
165
166
#define RESOLVER_NTASKS_PERCPU 32
#define UDPBUFFERS	       32768
#define EXCLBUFFERS	       32768
#else
#define RESOLVER_NTASKS_PERCPU 8
#define UDPBUFFERS	       1000
#define EXCLBUFFERS	       4096
167
168
#endif /* TUNE_LARGE */

169
170
171
172
173
174
175
176
177
178
179
180
/* RFC7828 defines timeout as 16-bit value specified in units of 100
 * milliseconds, so the maximum and minimum advertised and keepalive
 * timeouts are capped by the data type (it's ~109 minutes)
 */
#define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
#define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
#define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
#define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
#define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
#define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
#define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
#define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
181

182
/*%
183
184
185
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#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;                                          \
		}                                                              \
212
213
	} while (0)

214
215
216
217
218
219
220
221
222
223
#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;                                          \
		}                                                              \
224
225
	} while (0)

226
227
228
229
230
231
#define CHECKFATAL(op, msg)                         \
	do {                                        \
		result = (op);                      \
		if (result != ISC_R_SUCCESS)        \
			fatal(server, msg, result); \
	} while (0)
232

233
234
235
236
237
238
/*%
 * 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.
 */
239
#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
240

241
struct named_dispatch {
242
243
	isc_sockaddr_t addr;
	unsigned int dispatchgen;
244
245
	dns_dispatch_t *dispatch;
	ISC_LINK(struct named_dispatch) link;
246
247
};

248
struct named_cache {
249
250
251
252
	dns_cache_t *cache;
	dns_view_t *primaryview;
	bool needflush;
	bool adbsizeadjusted;
253
254
	dns_rdataclass_t rdclass;
	ISC_LINK(named_cache_t) link;
255
256
};

257
struct dumpcontext {
258
	isc_mem_t *mctx;
259
260
261
262
	bool dumpcache;
	bool dumpzones;
	bool dumpadb;
	bool dumpbad;
263
	bool dumpexpired;
264
265
	bool dumpfail;
	FILE *fp;
266
267
268
	ISC_LIST(struct viewlistentry) viewlist;
	struct viewlistentry *view;
	struct zonelistentry *zone;
269
270
271
272
273
	dns_dumpctx_t *mdctx;
	dns_db_t *db;
	dns_db_t *cache;
	isc_task_t *task;
	dns_dbversion_t *version;
274
275
276
};

struct viewlistentry {
277
278
279
	dns_view_t *view;
	ISC_LINK(struct viewlistentry) link;
	ISC_LIST(struct zonelistentry) zonelist;
280
281
282
};

struct zonelistentry {
283
284
	dns_zone_t *zone;
	ISC_LINK(struct zonelistentry) link;
285
286
};

287
288
/*%
 * Configuration context to retain for each view that allows
289
 * new zones to be added at runtime.
290
 */
Evan Hunt's avatar
Evan Hunt committed
291
typedef struct ns_cfgctx {
292
293
294
295
296
297
	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;
298
	cfg_aclconfctx_t *actx;
Evan Hunt's avatar
Evan Hunt committed
299
} ns_cfgctx_t;
300

301
302
303
304
305
306
/*%
 * 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);

307
308
309
310
311
312
/*%
 * 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 {
313
	named_server_t *server;
314
315
	bool reconfig;
	isc_refcount_t refs;
316
317
} ns_zoneload_t;

318
typedef struct {
319
	named_server_t *server;
320
321
322
323
324
} catz_cb_data_t;

typedef struct catz_chgzone_event {
	ISC_EVENT_COMMON(struct catz_chgzone_event);
	dns_catz_entry_t *entry;
325
326
327
328
	dns_catz_zone_t *origin;
	dns_view_t *view;
	catz_cb_data_t *cbd;
	bool mod;
329
330
} catz_chgzone_event_t;

Mark Andrews's avatar
Mark Andrews committed
331
332
typedef struct {
	unsigned int magic;
333
#define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
Mark Andrews's avatar
Mark Andrews committed
334
	isc_buffer_t **text;
335
	isc_result_t result;
Mark Andrews's avatar
Mark Andrews committed
336
337
} ns_dzarg_t;

338
339
340
/*
 * These zones should not leak onto the Internet.
 */
341
const char *empty_zones[] = {
342
	/* RFC 1918 */
343
344
345
346
347
348
	"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",
349

350
	/* RFC 6598 */
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
	"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",
372
373
	"127.100.IN-ADDR.ARPA",

374
	/* RFC 5735 and RFC 5737 */
375
376
377
378
	"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 */
379
380
	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
381
	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
382
383

	/* Local IPv6 Unicast Addresses */
384
385
386
387
	"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
388
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
389
390
391
392
	"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 */
393

394
	/* Example Prefix, RFC 3849. */
395
	"8.B.D.0.1.0.0.2.IP6.ARPA",
396

397
398
399
	/* RFC 7534 */
	"EMPTY.AS112.ARPA",

400
401
402
	/* RFC 8375 */
	"HOME.ARPA",

403
	NULL
404
405
};

Francis Dupont's avatar
Francis Dupont committed
406
ISC_PLATFORM_NORETURN_PRE static void
407
408
fatal(named_server_t *server, const char *msg,
      isc_result_t result) ISC_PLATFORM_NORETURN_POST;
David Lawrence's avatar
David Lawrence committed
409

410
411
static void
named_server_reload(isc_task_t *task, isc_event_t *event);
412

413
414
415
416
417
418
419
420
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);
421

422
423
424
425
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);
426

427
428
429
static isc_result_t
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
430

431
432
433
434
435
436
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);
437

438
439
440
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);
441

442
443
static isc_result_t
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
444

445
446
static void
end_reserved_dispatches(named_server_t *server, bool all);
447

448
449
static void
newzone_cfgctx_destroy(void **cfgp);
450

451
452
static inline isc_result_t
putstr(isc_buffer_t **b, const char *str);
453

454
455
static isc_result_t
putmem(isc_buffer_t **b, const char *str, size_t len);
456

457
458
static isc_result_t
putuint8(isc_buffer_t **b, uint8_t val);
459

460
461
static inline isc_result_t
putnull(isc_buffer_t **b);
462

463
464
static int
count_zones(const cfg_obj_t *conf);
465
466

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

470
471
static isc_result_t
nzd_writable(dns_view_t *view);
472

473
474
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
475

476
477
static isc_result_t
nzd_env_reopen(dns_view_t *view);
478

479
480
static void
nzd_env_close(dns_view_t *view);
481

482
483
static isc_result_t
nzd_close(MDB_txn **txnp, bool commit);
484

485
486
static isc_result_t
nzd_count(dns_view_t *view, int *countp);
487
#else  /* ifdef HAVE_LMDB */
488
489
static isc_result_t
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
490
#endif /* ifdef HAVE_LMDB */
Evan Hunt's avatar
Evan Hunt committed
491

492
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
493
494
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
495
496
 */
static isc_result_t
497
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
498
499
		   const cfg_obj_t *gconfig, const char *aclname,
		   const char *acltuplename, cfg_aclconfctx_t *actx,
500
501
		   isc_mem_t *mctx, dns_acl_t **aclp) {
	isc_result_t result;
502
	const cfg_obj_t *maps[4];
503
	const cfg_obj_t *aclobj = NULL;
504
	int i = 0;
505

506
	if (*aclp != NULL) {
507
		dns_acl_detach(aclp);
508
509
	}
	if (vconfig != NULL) {
510
		maps[i++] = cfg_tuple_get(vconfig, "options");
511
	}
512
	if (config != NULL) {
513
		const cfg_obj_t *options = NULL;
514
		(void)cfg_map_get(config, "options", &options);
515
		if (options != NULL) {
516
			maps[i++] = options;
517
518
519
520
521
522
523
524
		}
	}
	if (gconfig != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(gconfig, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
		}
525
526
	}
	maps[i] = NULL;
527

528
	(void)named_config_get(maps, aclname, &aclobj);
529
	if (aclobj == NULL) {
530
		/*
531
		 * No value available.	*aclp == NULL.
532
		 */
533
		return (ISC_R_SUCCESS);
534
	}
535

536
537
538
539
540
541
542
543
544
	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);
	}

545
546
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
				    aclp);
547
548
549
550
551
552
553
554
555
556
557

	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
558
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
559
560
			dns_acl_t **aclp) {
	isc_result_t result;
561
562
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
563
	int i = 0;
564

565
	if (*aclp != NULL) {
566
		dns_acl_detach(aclp);
567
568
	}
	if (vconfig != NULL) {
569
		maps[i++] = cfg_tuple_get(vconfig, "options");
570
	}
571
572
573
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
574
		if (options != NULL) {
575
			maps[i++] = options;
576
		}
577
578
579
	}
	maps[i] = NULL;

580
	(void)named_config_get(maps, "sortlist", &aclobj);
581
	if (aclobj == NULL) {
582
		return (ISC_R_SUCCESS);
583
	}
584

Automatic Updater's avatar
Automatic Updater committed
585
586
587
588
589
590
	/*
	 * 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.
	 */
591
592
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
				    aclp);
593
594
595
596

	return (result);
}

597
598
599
static isc_result_t
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
			 const char *confname, const char *conftuplename,
600
601
602
603
			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
	isc_result_t result;
	const cfg_obj_t *maps[3];
	const cfg_obj_t *obj = NULL;
604
	const cfg_listelt_t *element;
605
606
607
608
609
610
	int i = 0;
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_buffer_t b;
	const char *str;
	const cfg_obj_t *nameobj;
611

612
	if (*rbtp != NULL) {
613
		dns_rbt_destroy(rbtp);
614
615
	}
	if (vconfig != NULL) {
616
		maps[i++] = cfg_tuple_get(vconfig, "options");
617
	}
618
619
620
	if (config != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
621
		if (options != NULL) {
622
			maps[i++] = options;
623
		}
624
625
626
	}
	maps[i] = NULL;

627
	(void)named_config_get(maps, confname, &obj);
628
	if (obj == NULL) {
629
630
631
632
		/*
		 * No value available.	*rbtp == NULL.
		 */
		return (ISC_R_SUCCESS);
633
	}
634
635
636

	if (conftuplename != NULL) {
		obj = cfg_tuple_get(obj, conftuplename);
637
		if (cfg_obj_isvoid(obj)) {
638
			return (ISC_R_SUCCESS);
639
		}
640
641
642
	}

	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
643
	if (result != ISC_R_SUCCESS) {
644
		return (result);
645
	}
646

647
	name = dns_fixedname_initname(&fixed);
648
	for (element = cfg_list_first(obj); element != NULL;
649
650
	     element = cfg_list_next(element))
	{
651
652
		nameobj = cfg_listelt_value(element);
		str = cfg_obj_asstring(nameobj);
653
		isc_buffer_constinit(&b, str, strlen(str));
654
		isc_buffer_add(&b, strlen(str));
655
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
656
657
658
659
660
661
662
		/*
		 * 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.
		 */
663
664
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
665
			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
666
667
				    "failed to add %s for %s: %s", str,
				    confname, isc_result_totext(result));
668
669
			goto cleanup;
		}
670
671
672
673
	}

	return (result);

674
cleanup:
675
676
677
678
	dns_rbt_destroy(rbtp);
	return (result);
}

679
static isc_result_t
680
ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
681
682
	      unsigned char *digest, dns_rdata_ds_t *ds) {
	isc_result_t result;
683
	dns_rdata_dnskey_t keystruct;
684
685
686
687
688
689
690
691
692
693
694
695
	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;
696
697
698
699
700
701
702
	enum {
		INIT_DNSKEY,
		STATIC_DNSKEY,
		INIT_DS,
		STATIC_DS,
		TRUSTED
	} anchortype;
703

704
	REQUIRE(namestrp != NULL && *namestrp == NULL);
705
	REQUIRE(ds != NULL);
706
707

	/* if DNSKEY, flags; if DS, key tag */
708
	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
709
710

	/* if DNSKEY, protocol; if DS, algorithm */
711
	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
712
713

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

716
717
	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
	*namestrp = namestr;
718

719
720
721
722
	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));
723

Evan Hunt's avatar
Evan Hunt committed
724
	if (*initialp) {
725
		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
Automatic Updater's avatar
Automatic Updater committed
726

727
728
729
730
		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
731
			*initialp = false;
732
733
734
735
736
737
			anchortype = STATIC_DS;
		} else if (strcasecmp(atstr, "initial-key") == 0) {
			anchortype = INIT_DNSKEY;
		} else if (strcasecmp(atstr, "initial-ds") == 0) {
			anchortype = INIT_DS;
		} else {
738
			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
739
				    "key '%s': "
Automatic Updater's avatar
Automatic Updater committed
740
				    "invalid initialization method '%s'",
741
				    namestr, atstr);
Automatic Updater's avatar
Automatic Updater committed
742
743
744
			result = ISC_R_FAILURE;
			goto cleanup;
		}
745
746
	} else {
		anchortype = TRUSTED;
Automatic Updater's avatar
Automatic Updater committed
747
	}
748

749
750
751
	isc_buffer_init(&databuf, data, sizeof(data));
	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

752
753
	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
				.common.rdtype = dns_rdatatype_ds };
754
755
756

	ISC_LINK_INIT(&ds->common, link);

757
	switch (anchortype) {
758
759
760
761
762
763
764
765
766
	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
767

768
769
770
771
		/*
		 * The key data in keystruct is not dynamically allocated.
		 */
		keystruct.mctx = NULL;
772

773
774
		ISC_LINK_INIT(&keystruct.common, link);

775
		if (rdata1 > 0xffff) {
776
777
			CHECKM(ISC_R_RANGE, "key flags");
		}
778
		if (rdata1 & DNS_KEYFLAG_REVOKE) {
779
780
			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
		}
781
		if (rdata2 > 0xff) {
782
783
			CHECKM(ISC_R_RANGE, "key protocol");
		}
784
		if (rdata3 > 0xff) {
785
786
787
			CHECKM(ISC_R_RANGE, "key algorithm");
		}

788
789
790
		keystruct.flags = (uint16_t)rdata1;
		keystruct.protocol = (uint8_t)rdata2;
		keystruct.algorithm = (uint8_t)rdata3;
791

792
793
794
795
		if (!dst_algorithm_supported(keystruct.algorithm)) {
			CHECK(DST_R_UNSUPPORTEDALG);
		}

796
797
798
799
800
801
		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;

802
		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
803
804
					   keystruct.common.rdtype, &keystruct,
					   &rrdatabuf));
805
806
		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
					  digest, ds));
807
808
809
810
		break;

	case INIT_DS:
	case STATIC_DS:
811
		if (rdata1 > 0xffff) {
812
813
			CHECKM(ISC_R_RANGE, "key tag");
		}
814
		if (rdata2 > 0xff) {
815
816
			CHECKM(ISC_R_RANGE, "key algorithm");
		}
817
		if (rdata3 > 0xff) {
818
819
820
			CHECKM(ISC_R_RANGE, "digest type");
		}

821
822
823
		ds->key_tag = (uint16_t)rdata1;
		ds->algorithm = (uint8_t)rdata2;
		ds->digest_type = (uint8_t)rdata3;
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844

		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;
845
846
847
848
849
850
851
852
		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;
853
854
855
		}

		ds->length = r.length;
856
		ds->digest = digest;
857
858
859
		memmove(ds->digest, r.base, r.length);

		break;
860
861
862
863
864

	default:
		INSIST(0);
		ISC_UNREACHABLE();
	}
865
866
867

	return (ISC_R_SUCCESS);

868
cleanup:
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
	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
884
885
process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
	    const dns_name_t *keyname_match, dns_resolver_t *resolver,
886
	    bool managed) {
887
	dns_fixedname_t fkeyname;
888
889
890
891
892
893
894
	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;
895

896
	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
897
898
899
900

	switch (result) {
	case ISC_R_SUCCESS:
		/*
901
		 * Trust anchor was parsed correctly.
902
		 */
903
904
905
906
907
908
		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);
909
		}
910
911
912
913
914
915
916
917
918
		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
919
920
			    "ignoring %s for '%s': %s",
			    initializing ? "initial-key" : "static-key",
921
			    namestr, isc_result_totext(result));
922
923
924
925
926
		return (ISC_R_SUCCESS);
	case DST_R_NOCRYPTO:
		/*
		 * Crypto support is not available.
		 */
927
		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR<