server.c 397 KB
Newer Older
1
/*
2
 * Copyright (C) 1999-2018  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
/*! \file */
David Lawrence's avatar
David Lawrence committed
10

11
12
13
#include <config.h>

#include <stdlib.h>
14
#include <unistd.h>
15
#include <limits.h>
16
17
18
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
19

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

Evan Hunt's avatar
Evan Hunt committed
51
#include <isccfg/grammar.h>
52
#include <isccfg/namedconf.h>
53
54

#include <bind9/check.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/dnsrps.h>
64
#include <dns/dns64.h>
Evan Hunt's avatar
Evan Hunt committed
65
#include <dns/dyndb.h>
66
#include <dns/events.h>
67
#include <dns/forward.h>
68
#include <dns/fixedname.h>
69
#include <dns/journal.h>
70
#include <dns/keytable.h>
71
#include <dns/keyvalues.h>
72
#include <dns/lib.h>
73
#include <dns/master.h>
74
#include <dns/masterdump.h>
Evan Hunt's avatar
Evan Hunt committed
75
#include <dns/nta.h>
76
#include <dns/order.h>
77
#include <dns/peer.h>
78
#include <dns/portlist.h>
79
#include <dns/private.h>
80
#include <dns/rbt.h>
81
#include <dns/rdataclass.h>
82
#include <dns/rdatalist.h>
83
#include <dns/rdataset.h>
84
#include <dns/rdatastruct.h>
85
#include <dns/resolver.h>
86
#include <dns/rootns.h>
Evan Hunt's avatar
Evan Hunt committed
87
#include <dns/rriterator.h>
88
#include <dns/secalg.h>
89
#include <dns/soa.h>
90
#include <dns/stats.h>
91
#include <dns/tkey.h>
92
#include <dns/tsig.h>
Evan Hunt's avatar
Evan Hunt committed
93
#include <dns/ttl.h>
94
#include <dns/view.h>
95
#include <dns/zone.h>
96
#include <dns/zt.h>
97

98
#include <dst/dst.h>
99
#include <dst/result.h>
100

101
102
103
104
#include <ns/client.h>
#include <ns/listenlist.h>
#include <ns/interfacemgr.h>

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

#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 */
134

135
136
137
138
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

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

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

147
148
149
150
151
152
153
154
155
156
#ifdef TUNE_LARGE
#define RESOLVER_NTASKS 523
#define UDPBUFFERS 32768
#define EXCLBUFFERS 32768
#else
#define RESOLVER_NTASKS 31
#define UDPBUFFERS 1000
#define EXCLBUFFERS 4096
#endif /* TUNE_LARGE */

157
158
#define MAX_TCP_TIMEOUT 65535

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

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

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

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

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

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

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

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

232
233
234
235
struct dumpcontext {
	isc_mem_t			*mctx;
	isc_boolean_t			dumpcache;
	isc_boolean_t			dumpzones;
Evan Hunt's avatar
Evan Hunt committed
236
237
238
	isc_boolean_t			dumpadb;
	isc_boolean_t			dumpbad;
	isc_boolean_t			dumpfail;
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	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;
};

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

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

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

292
typedef struct {
293
	named_server_t *server;
294
295
296
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;
	isc_boolean_t mod;
} catz_chgzone_event_t;

305
306
307
/*
 * These zones should not leak onto the Internet.
 */
308
const char *empty_zones[] = {
309
	/* RFC 1918 */
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	"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",
328

329
330
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
	/* 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",

395
	/* RFC 5735 and RFC 5737 */
396
397
398
399
400
401
402
	"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 */
403
404

	/* Local IPv6 Unicast Addresses */
405
406
	"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
407
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
408
409
410
411
412
	"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 */
413

414
	/* Example Prefix, RFC 3849. */
415
	"8.B.D.0.1.0.0.2.IP6.ARPA",
416

417
418
419
	/* RFC 7534 */
	"EMPTY.AS112.ARPA",

420
	NULL
421
422
};

Francis Dupont's avatar
Francis Dupont committed
423
424
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
425
426

static void
427
named_server_reload(isc_task_t *task, isc_event_t *event);
428

429
static isc_result_t
430
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
431
432
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			isc_uint16_t family, ns_listenelt_t **target);
433
static isc_result_t
434
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
435
436
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			 isc_uint16_t family, ns_listenlist_t **target);
437

438
static isc_result_t
439
configure_forward(const cfg_obj_t *config, dns_view_t *view,
440
441
		  const dns_name_t *origin, const cfg_obj_t *forwarders,
		  const cfg_obj_t *forwardtype);
442

443
static isc_result_t
444
445
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
446

447
static isc_result_t
448
449
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
450
	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
Evan Hunt's avatar
Evan Hunt committed
451
452
	       isc_boolean_t added, isc_boolean_t old_rpz_ok,
	       isc_boolean_t modify);
453

454
455
456
457
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);

458
static isc_result_t
459
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
460

461
static void
462
end_reserved_dispatches(named_server_t *server, isc_boolean_t all);
463

464
static void
465
newzone_cfgctx_destroy(void **cfgp);
466

Mark Andrews's avatar
Mark Andrews committed
467
static inline isc_result_t
468
putstr(isc_buffer_t **b, const char *str);
469

470
static isc_result_t
471
472
473
474
475
putmem(isc_buffer_t **b, const char *str, size_t len);

static isc_result_t
putuint8(isc_buffer_t **b, isc_uint8_t val);

Mark Andrews's avatar
Mark Andrews committed
476
static inline isc_result_t
477
putnull(isc_buffer_t **b);
478

479
480
481
482
483
484
485
static int
count_zones(const cfg_obj_t *conf);

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

486
487
488
static isc_result_t
nzd_writable(dns_view_t *view);

489
490
491
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);

492
493
494
495
496
497
static isc_result_t
nzd_env_reopen(dns_view_t *view);

static void
nzd_env_close(dns_view_t *view);

498
499
500
501
502
503
static isc_result_t
nzd_close(MDB_txn **txnp, isc_boolean_t commit);

static isc_result_t
nzd_count(dns_view_t *view, int *countp);
#else
Evan Hunt's avatar
Evan Hunt committed
504
static isc_result_t
505
506
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
#endif
Evan Hunt's avatar
Evan Hunt committed
507

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

523
	if (*aclp != NULL) {
524
		dns_acl_detach(aclp);
525
526
	}
	if (vconfig != NULL) {
527
		maps[i++] = cfg_tuple_get(vconfig, "options");
528
	}
529
	if (config != NULL) {
530
		const cfg_obj_t *options = NULL;
531
		(void)cfg_map_get(config, "options", &options);
532
		if (options != NULL) {
533
			maps[i++] = options;
534
535
536
537
538
539
540
541
		}
	}
	if (gconfig != NULL) {
		const cfg_obj_t *options = NULL;
		(void)cfg_map_get(gconfig, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
		}
542
543
	}
	maps[i] = NULL;
544

545
	(void)named_config_get(maps, aclname, &aclobj);
546
	if (aclobj == NULL) {
547
		/*
548
		 * No value available.	*aclp == NULL.
549
		 */
550
		return (ISC_R_SUCCESS);
551
	}
552

553
554
555
556
557
558
559
560
561
	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);
	}

562
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
563
564
565
566
567
568
569
570
571
572
573
574
				    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
575
576
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
{
	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;

595
	(void)named_config_get(maps, "sortlist", &aclobj);
596
597
598
	if (aclobj == NULL)
		return (ISC_R_SUCCESS);

Automatic Updater's avatar
Automatic Updater committed
599
600
601
602
603
604
	/*
	 * 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.
	 */
605
	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
606
				    actx, mctx, 3, aclp);
607
608
609
610

	return (result);
}

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
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;

639
	(void)named_config_get(maps, confname, &obj);
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
	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);

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	for (element = cfg_list_first(obj);
	     element != NULL;
	     element = cfg_list_next(element)) {
		nameobj = cfg_listelt_value(element);
		str = cfg_obj_asstring(nameobj);
663
		isc_buffer_constinit(&b, str, strlen(str));
664
		isc_buffer_add(&b, strlen(str));
665
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
666
667
668
669
670
671
672
		/*
		 * 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.
		 */
673
674
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
675
			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
676
677
678
679
				    "failed to add %s for %s: %s",
				    str, confname, isc_result_totext(result));
			goto cleanup;
		}
Automatic Updater's avatar
Automatic Updater committed
680

681
682
683
684
685
686
687
	}

	return (result);

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

689
690
}

691
static isc_result_t
692
693
dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
694
695
{
	dns_rdataclass_t viewclass;
696
	dns_rdata_dnskey_t keystruct;
697
	isc_uint32_t flags, proto, alg;
698
	const char *keystr, *keynamestr;
699
700
701
702
703
704
705
706
707
708
709
	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;

710
711
	INSIST(target != NULL && *target == NULL);

712
713
714
715
716
717
	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
718
719
720
721
	if (managed) {
		const char *initmethod;
		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));

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

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

	ISC_LINK_INIT(&keystruct.common, link);

748
	if (flags > 0xffff)
749
		CHECKM(ISC_R_RANGE, "key flags");
750
	if (proto > 0xff)
751
		CHECKM(ISC_R_RANGE, "key protocol");
752
	if (alg > 0xff)
753
		CHECKM(ISC_R_RANGE, "key algorithm");
754
755
756
	keystruct.flags = (isc_uint16_t)flags;
	keystruct.protocol = (isc_uint8_t)proto;
	keystruct.algorithm = (isc_uint8_t)alg;
757
758
759
760

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

761
	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
762
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
763
764
765
766
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

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

775
776
777
778
779
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
780
	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
781
	isc_buffer_add(&namebuf, strlen(keynamestr));
782
	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
783
784
785
	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
			      mctx, &dstkey));

786
	*target = dstkey;
787
788
789
	return (ISC_R_SUCCESS);

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

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

	return (result);
}

Evan Hunt's avatar
Evan Hunt committed
814
815
816
817
818
/*
 * 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.
 */
819
820
static isc_result_t
load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
821
	       dns_view_t *view, isc_boolean_t managed,
822
	       const dns_name_t *keyname, isc_mem_t *mctx)
823
824
{
	const cfg_listelt_t *elt, *elt2;
825
826
	const cfg_obj_t *key, *keylist;
	dst_key_t *dstkey = NULL;
827
828
829
830
	isc_result_t result;
	dns_keytable_t *secroots = NULL;

	CHECK(dns_view_getsecroots(view, &secroots));
831
832
833

	for (elt = cfg_list_first(keys);
	     elt != NULL;
Evan Hunt's avatar
Evan Hunt committed
834
835
	     elt = cfg_list_next(elt))
	{
836
837
838
839
		keylist = cfg_listelt_value(elt);

		for (elt2 = cfg_list_first(keylist);
		     elt2 != NULL;
Evan Hunt's avatar
Evan Hunt committed
840
841
		     elt2 = cfg_list_next(elt2))
		{
842
			key = cfg_listelt_value(elt2);
843
844
845
846
847
848
			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
849
			if (result != ISC_R_SUCCESS) {
850
				goto cleanup;
Evan Hunt's avatar
Evan Hunt committed
851
			}
852

853
854
855
856
			/*
			 * If keyname was specified, we only add that key.
			 */
			if (keyname != NULL &&
Automatic Updater's avatar
Automatic Updater committed
857
			    !dns_name_equal(keyname, dst_key_name(dstkey)))
858
859
860
861
862
			{
				dst_key_free(&dstkey);
				continue;
			}

Evan Hunt's avatar
Evan Hunt committed
863
864
865
866
867
868
869
870
			/*
			 * 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.
			 */
			CHECK(dns_keytable_add2(secroots, managed,
						managed, &dstkey));
871
872
873
874
		}
	}

 cleanup:
Evan Hunt's avatar
Evan Hunt committed
875
	if (dstkey != NULL) {
876
		dst_key_free(&dstkey);
Evan Hunt's avatar
Evan Hunt committed
877
878
	}
	if (secroots != NULL) {
879
		dns_keytable_detach(&secroots);
Evan Hunt's avatar
Evan Hunt committed
880
881
	}
	if (result == DST_R_NOCRYPTO) {
882
		result = ISC_R_SUCCESS;
Evan Hunt's avatar
Evan Hunt committed
883
	}
884
	return (result);
885
886
}

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
/*%
 * Check whether a key has been successfully loaded.
 */
static isc_boolean_t
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)
		return (ISC_FALSE);

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

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

	return (ISC_TF(result == ISC_R_SUCCESS));
}

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

933
	/* We don't need trust anchors for the _bind view */
934
935
	if (strcmp(view->name, "_bind") == 0 &&
	    view->rdclass == dns_rdataclass_chaos) {
936
937
		return (ISC_R_SUCCESS);
	}
938

939
	if (vconfig != NULL) {
940
		voptions = cfg_tuple_get(vconfig, "options");
941
		if (voptions != NULL) {
942
943
			(void) cfg_map_get(voptions, "trusted-keys",
					   &view_keys);
944
945
			(void) cfg_map_get(voptions, "managed-keys",
					   &view_managed_keys);
946
947
948
			maps[i++] = voptions;
		}
	}
949

950
951
	if (config != NULL) {
		(void)cfg_map_get(config, "trusted-keys", &global_keys);
952
		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
953
954
955
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
956
		}
957
	}
958

959
	maps[i++] = named_g_defaults;
960
961
	maps[i] = NULL;

962
	result = dns_view_initsecroots(view, mctx);
963
	if (result != ISC_R_SUCCESS) {
964
965
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
966
967
968
969
			      "couldn't create keytable");
		return (ISC_R_UNEXPECTED);
	}

970
	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
Evan Hunt's avatar
Evan Hunt committed
971
	if (result != ISC_R_SUCCESS) {
972
973
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
Evan Hunt's avatar
Evan Hunt committed
974
975
976
977
			      "couldn't create NTA table");
		return (ISC_R_UNEXPECTED);
	}

978
979
980
981
982
	if (auto_root && view->rdclass == dns_rdataclass_in) {
		const cfg_obj_t *builtin_keys = NULL;
		const cfg_obj_t *builtin_managed_keys = NULL;

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

993
994
995
996
			(void)cfg_map_get(bindkeys, "trusted-keys",
					  &builtin_keys);
			(void)cfg_map_get(bindkeys, "managed-keys",
					  &builtin_managed_keys);
997
998
999

			if ((builtin_keys == NULL) &&
			    (builtin_managed_keys == NULL))
1000
				isc_log_write(named_g_lctx,
1001
					      DNS_LOGCATEGORY_SECURITY,
1002
					      NAMED_LOGMODULE_SERVER,
1003
1004
1005
1006
1007
1008
1009
1010
1011
					      ISC_LOG_WARNING,
					      "dnssec-validation auto: "
					      "WARNING: root zone key "
					      "not found");
		}

		if ((builtin_keys == NULL) &&
		    (builtin_managed_keys == NULL))
		{
1012
1013
			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1014
1015
1016
				      "using built-in root key for view %s",
				      view->name);

1017
			(void)cfg_map_get(named_g_config, "trusted-keys",
1018
					  &builtin_keys);
1019
			(void)cfg_map_get(named_g_config, "managed-keys",
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
					  &builtin_managed_keys);
		}

		if (builtin_keys != NULL)
			CHECK(load_view_keys(builtin_keys, vconfig, view,
					     ISC_FALSE, dns_rootname, mctx));
		if (builtin_managed_keys != NULL)
			CHECK(load_view_keys(builtin_managed_keys, vconfig,
					     view, ISC_TRUE, dns_rootname,
					     mctx));
1030
1031

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

	CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
			     NULL, mctx));
	CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
			     NULL, mctx));

1045
1046
	if (view->rdclass == dns_rdataclass_in) {
		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
1047
				     NULL, mctx));
1048
		CHECK(load_view_keys(global_managed_keys, vconfig, view,
1049
				     ISC_TRUE, NULL, mctx));
1050
1051
1052
	}

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

1067
	} else if (directory != NULL) {
1068
		if (!isc_file_isdirwritable(directory)) {
1069
1070
1071
			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
				      "managed-keys-directory '%s' "
1072
				      "is not writable", directory);
1073
1074
1075
			result = ISC_R_NOPERM;
			goto cleanup;
		}
1076
	}
Evan Hunt's avatar
Evan Hunt committed
1077

1078
	CHECK(add_keydata_zone(view, directory, named_g_mctx));
Automatic Updater's avatar
Automatic Updater committed
1079

1080
1081
  cleanup:
	return (result);
1082
}
1083

1084
static isc_result_t
1085
mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1086
1087
	const cfg_listelt_t *element;
	const cfg_obj_t *obj;
1088
1089
1090
1091
1092
1093
	const char *str;
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_boolean_t value;
	isc_result_t result;
	isc_buffer_t b;
Automatic Updater's avatar
Automatic Updater committed
1094

1095
1096
1097
1098
1099
1100
1101
1102
	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	for (element = cfg_list_first(mbs);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		obj = cfg_listelt_value(element);
		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1103
		isc_buffer_constinit(&b, str, strlen(str));
1104
		isc_buffer_add(&b, strlen(str));
1105
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1106
1107
1108
1109
1110
		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
	}

	result = ISC_R_SUCCESS;
Automatic Updater's avatar
Automatic Updater committed
1111

1112
1113
1114
 cleanup:
	return (result);
}
1115

1116
/*%
1117
1118
1119
 * Get a dispatch appropriate for the resolver of a given view.
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
1120
1121
get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
1122
			      isc_boolean_t is_firstview)
1123
{
1124
	isc_result_t result = ISC_R_FAILURE;
1125
1126
1127
	dns_dispatch_t *disp;
	isc_sockaddr_t sa;
	unsigned int attrs, attrmask;
1128
	const cfg_obj_t *obj = NULL;
1129
	unsigned int maxdispatchbuffers = UDPBUFFERS;
Evan Hunt's avatar
Evan Hunt committed
1130
	isc_dscp_t dscp = -1;
1131
1132
1133

	switch (af) {
	case AF_INET:
1134
		result = named_config_get(maps, "query-source", &obj);
1135
		INSIST(result == ISC_R_SUCCESS);