server.c 402 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8
9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10
11
 */

12
/*! \file */
David Lawrence's avatar
David Lawrence committed
13

14
15
#include <config.h>

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

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

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

#include <bind9/check.h>
58

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

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

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

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

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

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

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

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

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

160
161
#define MAX_TCP_TIMEOUT 65535

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

426
	NULL
427
428
};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void
nzd_env_close(dns_view_t *view);

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

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

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

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

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

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

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

	return (result);
}

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

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

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

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

	return (result);
}

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

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

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

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

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

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

686
687
688
689
690
691
692
	}

	return (result);

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

694
695
}

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

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

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

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

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

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

	ISC_LINK_INIT(&keystruct.common, link);

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

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

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

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

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

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

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

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

	return (result);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

945
	if (vconfig != NULL) {
946
		voptions = cfg_tuple_get(vconfig, "options");
947
		if (voptions != NULL) {
948
949
			(void) cfg_map_get(voptions, "trusted-keys",
					   &view_keys);
950
951
			(void) cfg_map_get(voptions, "managed-keys",
					   &view_managed_keys);
952
953
954
			maps[i++] = voptions;
		}
	}
955

956
957
	if (config != NULL) {
		(void)cfg_map_get(config, "trusted-keys", &global_keys);
958
		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
959
960
961
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
962
		}
963
	}
964

965
	maps[i++] = named_g_defaults;
966
967
	maps[i] = NULL;

968
	result = dns_view_initsecroots(view, mctx);
969
	if (result != ISC_R_SUCCESS) {
970
971
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
972
973
974
975
			      "couldn't create keytable");
		return (ISC_R_UNEXPECTED);
	}

976
	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
Evan Hunt's avatar
Evan Hunt committed
977
	if (result != ISC_R_SUCCESS) {
978
979
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
980
981
982
983
			      "couldn't create NTA table");
		return (ISC_R_UNEXPECTED);
	}

984
985
986
987
988
	if (auto_root && view->rdclass == dns_rdataclass_in) {
		const cfg_obj_t *builtin_keys = NULL;
		const cfg_obj_t *builtin_managed_keys = NULL;

		/*
989
		 * If bind.keys exists and is populated, it overrides
990
		 * the managed-keys clause hard-coded in named_g_config.
991
992
		 */
		if (bindkeys != NULL) {
993
994
			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
995
996
				      "obtaining root key for view %s "
				      "from '%s'",
997
				      view->name, named_g_server->bindkeysfile);
998

999
1000
1001
1002
			(void)cfg_map_get(bindkeys, "trusted-keys",
					  &builtin_keys);
			(void)cfg_map_get(bindkeys, "managed-keys",
					  &builtin_managed_keys);
1003
1004
1005

			if ((builtin_keys == NULL) &&
			    (builtin_managed_keys == NULL))
1006
				isc_log_write(named_g_lctx,
1007
					      DNS_LOGCATEGORY_SECURITY,
1008
					      NAMED_LOGMODULE_SERVER,
1009
1010
1011
1012
1013
1014
1015
1016
1017
					      ISC_LOG_WARNING,
					      "dnssec-validation auto: "
					      "WARNING: root zone key "
					      "not found");
		}

		if ((builtin_keys == NULL) &&
		    (builtin_managed_keys == NULL))
		{
1018
1019
			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1020
1021
1022
				      "using built-in root key for view %s",
				      view->name);

1023
			(void)cfg_map_get(named_g_config, "trusted-keys",
1024
					  &builtin_keys);
1025
			(void)cfg_map_get(named_g_config, "managed-keys",
1026
1027
1028
1029
1030
					  &builtin_managed_keys);
		}

		if (builtin_keys != NULL)
			CHECK(load_view_keys(builtin_keys, vconfig, view,
1031
					     false, dns_rootname, mctx));
1032
1033
		if (builtin_managed_keys != NULL)
			CHECK(load_view_keys(builtin_managed_keys, vconfig,
1034
					     view, true, dns_rootname,
1035
					     mctx));
1036
1037

		if (!keyloaded(view, dns_rootname)) {
1038
1039
			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1040
1041
1042
1043
				      "root key not loaded");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
1044
1045
	}

1046
	CHECK(load_view_keys(view_keys, vconfig, view, false,
1047
			     NULL, mctx));
1048
	CHECK(load_view_keys(view_managed_keys, vconfig, view, true,
1049
1050
			     NULL, mctx));

1051
	if (view->rdclass == dns_rdataclass_in) {
1052
		CHECK(load_view_keys(global_keys, vconfig, view, false,
1053
				     NULL, mctx));
1054
		CHECK(load_view_keys(global_managed_keys, vconfig, view,
1055
				     true, NULL, mctx));
1056
1057
1058
	}

	/*
Evan Hunt's avatar
Evan Hunt committed
1059
	 * Add key zone for managed keys.
1060
1061
	 */
	obj = NULL;
1062
	(void)named_config_get(maps, "managed-keys-directory", &obj);
1063
1064
1065
1066
	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
	if (directory != NULL)
		result = isc_file_isdirectory(directory);
	if (result != ISC_R_SUCCESS) {
1067
1068
		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1069
1070
1071
1072
			      "invalid managed-keys-directory %s: %s",
			      directory, isc_result_totext(result));
		goto cleanup;

1073
	} else if (directory != NULL) {
1074
		if (!isc_file_isdirwritable(directory)) {
1075
1076
1077
			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
				      "managed-keys-directory '%s' "
1078
				      "is not writable", directory);
1079
1080
1081
			result = ISC_R_NOPERM;
			goto cleanup;
		}
1082
	}
Evan Hunt's avatar
Evan Hunt committed
1083

1084
	CHECK(add_keydata_zone(view, directory, named_g_mctx));
Automatic Updater's avatar
Automatic Updater committed
1085

1086
1087
  cleanup:
	return (result);
1088
}
1089

1090
static isc_result_t
1091
mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {