server.c 264 KB
Newer Older
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
16
17
 */

Evan Hunt's avatar
Evan Hunt committed
18
/* $Id$ */
19
20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

22
23
24
#include <config.h>

#include <stdlib.h>
25
#include <unistd.h>
26
#include <limits.h>
27
28
29
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
30

31
#include <isc/app.h>
32
#include <isc/base64.h>
33
#include <isc/dir.h>
34
#include <isc/entropy.h>
35
#include <isc/file.h>
36
#include <isc/hash.h>
37
#include <isc/hex.h>
38
#include <isc/httpd.h>
39
#include <isc/lex.h>
40
#include <isc/parseint.h>
41
#include <isc/portset.h>
42
#include <isc/print.h>
43
#include <isc/random.h>
44
#include <isc/refcount.h>
45
#include <isc/resource.h>
46
#include <isc/sha2.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
#include <isc/xml.h>
56

57
58
59
60
61
62
#ifdef AES_SIT
#include <isc/aes.h>
#else
#include <isc/hmacsha.h>
#endif

63
#include <isccfg/namedconf.h>
64
65

#include <bind9/check.h>
66

67
#include <dns/acache.h>
68
#include <dns/adb.h>
69
#include <dns/cache.h>
70
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
71
#include <dns/dispatch.h>
72
#include <dns/dlz.h>
73
#include <dns/dns64.h>
74
#include <dns/forward.h>
75
#include <dns/journal.h>
76
#include <dns/keytable.h>
77
#include <dns/keyvalues.h>
78
#include <dns/lib.h>
79
#include <dns/master.h>
80
#include <dns/masterdump.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>
92
#include <dns/secalg.h>
93
#include <dns/soa.h>
94
#include <dns/stats.h>
95
#include <dns/tkey.h>
96
#include <dns/tsig.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
#include <named/client.h>
105
#include <named/config.h>
106
#include <named/control.h>
Evan Hunt's avatar
Evan Hunt committed
107
#include <named/geoip.h>
108
#include <named/interfacemgr.h>
109
#include <named/log.h>
110
#include <named/logconf.h>
111
#include <named/lwresd.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
120
121
122
#ifdef HAVE_LIBSCF
#include <named/ns_smf_globals.h>
#include <stdlib.h>
#endif
Evan Hunt's avatar
Evan Hunt committed
123
124
125
#ifdef HAVE_GEOIP
#include <named/geoip.h>
#endif /* HAVE_GEOIP */
126

127
128
129
130
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

131
132
133
134
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif

135
136
137
138
139
140
141
142
143
144
#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 */

145
/*%
146
147
148
149
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
#define CHECK(op) \
150
151
	do { result = (op);					 \
	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
152
153
154
	} while (0)

#define CHECKM(op, msg) \
155
	do { result = (op);					  \
156
157
158
159
160
161
162
163
164
165
166
	       if (result != ISC_R_SUCCESS) {			  \
			isc_log_write(ns_g_lctx,		  \
				      NS_LOGCATEGORY_GENERAL,	  \
				      NS_LOGMODULE_SERVER,	  \
				      ISC_LOG_ERROR,		  \
				      "%s: %s", msg,		  \
				      isc_result_totext(result)); \
			goto cleanup;				  \
		}						  \
	} while (0)						  \

Mark Andrews's avatar
Mark Andrews committed
167
#define CHECKMF(op, msg, file) \
168
	do { result = (op);					  \
Mark Andrews's avatar
Mark Andrews committed
169
170
171
172
173
174
175
176
177
178
179
	       if (result != ISC_R_SUCCESS) {			  \
			isc_log_write(ns_g_lctx,		  \
				      NS_LOGCATEGORY_GENERAL,	  \
				      NS_LOGMODULE_SERVER,	  \
				      ISC_LOG_ERROR,		  \
				      "%s '%s': %s", msg, file,	  \
				      isc_result_totext(result)); \
			goto cleanup;				  \
		}						  \
	} while (0)						  \

180
#define CHECKFATAL(op, msg) \
181
	do { result = (op);					  \
182
183
184
185
	       if (result != ISC_R_SUCCESS)			  \
			fatal(msg, result);			  \
	} while (0)						  \

186
187
188
189
190
191
/*%
 * 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
192
#define MAX_ADB_SIZE_FOR_CACHESHARE	8388608U
193

194
195
196
197
198
199
200
struct ns_dispatch {
	isc_sockaddr_t			addr;
	unsigned int			dispatchgen;
	dns_dispatch_t			*dispatch;
	ISC_LINK(struct ns_dispatch)	link;
};

201
202
203
204
205
206
207
208
struct ns_cache {
	dns_cache_t			*cache;
	dns_view_t			*primaryview;
	isc_boolean_t			needflush;
	isc_boolean_t			adbsizeadjusted;
	ISC_LINK(ns_cache_t)		link;
};

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
struct dumpcontext {
	isc_mem_t			*mctx;
	isc_boolean_t			dumpcache;
	isc_boolean_t			dumpzones;
	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;
};

235
236
/*%
 * Configuration context to retain for each view that allows
237
 * new zones to be added at runtime.
238
239
240
241
 */
struct cfg_context {
	isc_mem_t *			mctx;
	cfg_parser_t *			parser;
242
243
244
	cfg_obj_t *			config;
	cfg_parser_t *			nzparser;
	cfg_obj_t *			nzconfig;
245
	cfg_aclconfctx_t *		actx;
246
247
};

248
249
250
251
252
253
254
255
256
257
/*%
 * 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 {
		ns_server_t *server;
		isc_refcount_t refs;
} ns_zoneload_t;

258
259
260
/*
 * These zones should not leak onto the Internet.
 */
261
const char *empty_zones[] = {
262
	/* RFC 1918 */
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	"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",
281

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
	/* 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",

348
	/* RFC 5735 and RFC 5737 */
349
350
351
352
353
354
355
	"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 */
356
357

	/* Local IPv6 Unicast Addresses */
358
359
	"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
360
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
361
362
363
364
365
	"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 */
366

367
	/* Example Prefix, RFC 3849. */
368
	"8.B.D.0.1.0.0.2.IP6.ARPA",
369

370
	NULL
371
372
};

Francis Dupont's avatar
Francis Dupont committed
373
374
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
375
376
377

static void
ns_server_reload(isc_task_t *task, isc_event_t *event);
378

379
static isc_result_t
380
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
381
382
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			isc_uint16_t family, ns_listenelt_t **target);
383
static isc_result_t
384
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
385
386
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			 isc_uint16_t family, ns_listenlist_t **target);
387

388
static isc_result_t
389
390
configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
391

392
static isc_result_t
393
394
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
395

396
static isc_result_t
397
398
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
399
400
	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
	       isc_boolean_t added, isc_boolean_t old_rpz_ok);
401

402
static isc_result_t
403
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
404

405
406
407
static void
end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);

408
static void
409
newzone_cfgctx_destroy(void **cfgp);
410

411
412
413
static isc_result_t
putstr(isc_buffer_t *b, const char *str);

Evan Hunt's avatar
Evan Hunt committed
414
415
416
isc_result_t
add_comment(FILE *fp, const char *viewname);

417
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
418
419
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
420
421
 */
static isc_result_t
422
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
423
424
		   const char *aclname, const char *acltuplename,
		   cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
425
426
{
	isc_result_t result;
427
428
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
429
430
	int i = 0;

431
432
	if (*aclp != NULL)
		dns_acl_detach(aclp);
433
434
435
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
436
		const cfg_obj_t *options = NULL;
437
		(void)cfg_map_get(config, "options", &options);
438
439
440
441
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i] = NULL;
442

443
	(void)ns_config_get(maps, aclname, &aclobj);
444
	if (aclobj == NULL)
445
		/*
446
		 * No value available.	*aclp == NULL.
447
		 */
448
449
		return (ISC_R_SUCCESS);

450
451
452
453
454
455
456
457
458
	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);
	}

459
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
460
461
462
463
464
465
466
467
468
469
470
471
				    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
472
473
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
{
	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;

	(void)ns_config_get(maps, "sortlist", &aclobj);
	if (aclobj == NULL)
		return (ISC_R_SUCCESS);

Automatic Updater's avatar
Automatic Updater committed
496
497
498
499
500
501
	/*
	 * 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.
	 */
502
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
503
				    actx, mctx, 3, aclp);
504
505
506
507

	return (result);
}

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
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;

	(void)ns_config_get(maps, confname, &obj);
	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);
560
		isc_buffer_constinit(&b, str, strlen(str));
561
		isc_buffer_add(&b, strlen(str));
562
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
563
564
565
566
567
568
569
		/*
		 * 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.
		 */
570
571
572
573
574
575
576
		result = dns_rbt_addname(*rbtp, name, (void *)1);
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
				    "failed to add %s for %s: %s",
				    str, confname, isc_result_totext(result));
			goto cleanup;
		}
Automatic Updater's avatar
Automatic Updater committed
577

578
579
580
581
582
583
584
	}

	return (result);

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

586
587
}

588
static isc_result_t
589
590
dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
591
592
{
	dns_rdataclass_t viewclass;
593
	dns_rdata_dnskey_t keystruct;
594
	isc_uint32_t flags, proto, alg;
595
	const char *keystr, *keynamestr;
596
597
598
599
600
601
602
603
604
605
606
	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;

607
608
	INSIST(target != NULL && *target == NULL);

609
610
611
612
613
614
	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
615
616
617
618
	if (managed) {
		const char *initmethod;
		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));

619
		if (strcasecmp(initmethod, "initial-key") != 0) {
Automatic Updater's avatar
Automatic Updater committed
620
621
622
623
624
625
626
627
			cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
				    "managed key '%s': "
				    "invalid initialization method '%s'",
				    keynamestr, initmethod);
			result = ISC_R_FAILURE;
			goto cleanup;
		}
	}
628

629
	if (vconfig == NULL)
630
		viewclass = dns_rdataclass_in;
631
	else {
632
		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
633
634
		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
					 &viewclass));
635
	}
636
	keystruct.common.rdclass = viewclass;
637
	keystruct.common.rdtype = dns_rdatatype_dnskey;
638
	/*
639
	 * The key data in keystruct is not dynamically allocated.
640
641
642
643
644
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

645
	if (flags > 0xffff)
646
		CHECKM(ISC_R_RANGE, "key flags");
647
	if (proto > 0xff)
648
		CHECKM(ISC_R_RANGE, "key protocol");
649
	if (alg > 0xff)
650
		CHECKM(ISC_R_RANGE, "key algorithm");
651
652
653
	keystruct.flags = (isc_uint16_t)flags;
	keystruct.protocol = (isc_uint8_t)proto;
	keystruct.algorithm = (isc_uint8_t)alg;
654
655
656
657

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

658
	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
659
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
660
661
662
663
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

664
665
666
667
	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
	     keystruct.algorithm == DST_ALG_RSAMD5) &&
	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
668
669
			    "%s key '%s' has a weak exponent",
			    managed ? "managed" : "trusted",
670
671
			    keynamestr);

672
673
674
675
676
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
677
	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
678
	isc_buffer_add(&namebuf, strlen(keynamestr));
679
	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
680
681
682
	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
			      mctx, &dstkey));

683
	*target = dstkey;
684
685
686
	return (ISC_R_SUCCESS);

 cleanup:
687
688
	if (result == DST_R_NOCRYPTO) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
689
690
			    "ignoring %s key for '%s': no crypto support",
			    managed ? "managed" : "trusted",
691
			    keynamestr);
692
693
694
695
696
	} else if (result == DST_R_UNSUPPORTEDALG) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
			    "skipping %s key for '%s': %s",
			    managed ? "managed" : "trusted",
			    keynamestr, isc_result_totext(result));
697
698
	} else {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
699
700
			    "configuring %s key for '%s': %s",
			    managed ? "managed" : "trusted",
701
702
703
			    keynamestr, isc_result_totext(result));
		result = ISC_R_FAILURE;
	}
704
705
706
707
708
709
710

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

	return (result);
}

711
712
static isc_result_t
load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
713
714
	       dns_view_t *view, isc_boolean_t managed,
	       dns_name_t *keyname, isc_mem_t *mctx)
715
716
{
	const cfg_listelt_t *elt, *elt2;
717
718
	const cfg_obj_t *key, *keylist;
	dst_key_t *dstkey = NULL;
719
720
721
722
	isc_result_t result;
	dns_keytable_t *secroots = NULL;

	CHECK(dns_view_getsecroots(view, &secroots));
723
724
725
726
727
728
729
730
731
732

	for (elt = cfg_list_first(keys);
	     elt != NULL;
	     elt = cfg_list_next(elt)) {
		keylist = cfg_listelt_value(elt);

		for (elt2 = cfg_list_first(keylist);
		     elt2 != NULL;
		     elt2 = cfg_list_next(elt2)) {
			key = cfg_listelt_value(elt2);
733
734
735
736
737
738
739
740
			result = dstkey_fromconfig(vconfig, key, managed,
						   &dstkey, mctx);
			if (result ==  DST_R_UNSUPPORTEDALG) {
				result = ISC_R_SUCCESS;
				continue;
			}
			if (result != ISC_R_SUCCESS)
				goto cleanup;
741

742
743
744
745
			/*
			 * If keyname was specified, we only add that key.
			 */
			if (keyname != NULL &&
Automatic Updater's avatar
Automatic Updater committed
746
			    !dns_name_equal(keyname, dst_key_name(dstkey)))
747
748
749
750
751
			{
				dst_key_free(&dstkey);
				continue;
			}

752
			CHECK(dns_keytable_add(secroots, managed, &dstkey));
753
754
755
756
		}
	}

 cleanup:
757
758
	if (dstkey != NULL)
		dst_key_free(&dstkey);
759
760
	if (secroots != NULL)
		dns_keytable_detach(&secroots);
761
762
	if (result == DST_R_NOCRYPTO)
		result = ISC_R_SUCCESS;
763
	return (result);
764
765
}

766
/*%
767
 * Configure DNSSEC keys for a view.
768
 *
769
 * The per-view configuration values and the server-global defaults are read
770
 * from 'vconfig' and 'config'.
771
772
 */
static isc_result_t
773
774
configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
775
776
			  isc_boolean_t auto_dlv, isc_boolean_t auto_root,
			  isc_mem_t *mctx)
777
{
778
	isc_result_t result = ISC_R_SUCCESS;
779
780
	const cfg_obj_t *view_keys = NULL;
	const cfg_obj_t *global_keys = NULL;
781
	const cfg_obj_t *view_managed_keys = NULL;
782
	const cfg_obj_t *global_managed_keys = NULL;
783
	const cfg_obj_t *maps[4];
784
	const cfg_obj_t *voptions = NULL;
785
	const cfg_obj_t *options = NULL;
786
787
	const cfg_obj_t *obj = NULL;
	const char *directory;
788
	int i = 0;
789

790
	/* We don't need trust anchors for the _bind view */
791
792
	if (strcmp(view->name, "_bind") == 0 &&
	    view->rdclass == dns_rdataclass_chaos) {
793
794
		return (ISC_R_SUCCESS);
	}
795

796
	if (vconfig != NULL) {
797
		voptions = cfg_tuple_get(vconfig, "options");
798
		if (voptions != NULL) {
799
800
			(void) cfg_map_get(voptions, "trusted-keys",
					   &view_keys);
801
802
			(void) cfg_map_get(voptions, "managed-keys",
					   &view_managed_keys);
803
804
805
			maps[i++] = voptions;
		}
	}
806

807
808
	if (config != NULL) {
		(void)cfg_map_get(config, "trusted-keys", &global_keys);
809
		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
810
811
812
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
813
		}
814
	}
815

816
817
818
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

819
	result = dns_view_initsecroots(view, mctx);
820
821
822
823
824
825
826
	if (result != ISC_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "couldn't create keytable");
		return (ISC_R_UNEXPECTED);
	}

827
	if (auto_dlv && view->rdclass == dns_rdataclass_in) {
828
829
830
		const cfg_obj_t *builtin_keys = NULL;
		const cfg_obj_t *builtin_managed_keys = NULL;

831
		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
832
			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
833
			      "using built-in DLV key for view %s",
834
			      view->name);
835
836

		/*
837
		 * If bind.keys exists, it overrides the managed-keys
838
839
		 * clause hard-coded in ns_g_config.
		 */
840
		if (bindkeys != NULL) {
841
842
			(void)cfg_map_get(bindkeys, "trusted-keys",
					  &builtin_keys);
843
844
845
			(void)cfg_map_get(bindkeys, "managed-keys",
					  &builtin_managed_keys);
		} else {
846
847
			(void)cfg_map_get(ns_g_config, "trusted-keys",
					  &builtin_keys);
848
849
850
851
			(void)cfg_map_get(ns_g_config, "managed-keys",
					  &builtin_managed_keys);
		}

852
853
		if (builtin_keys != NULL)
			CHECK(load_view_keys(builtin_keys, vconfig, view,
854
					     ISC_FALSE, view->dlv, mctx));
855
856
		if (builtin_managed_keys != NULL)
			CHECK(load_view_keys(builtin_managed_keys, vconfig,
857
					     view, ISC_TRUE, view->dlv, mctx));
858
859
	}

860
861
862
863
864
	if (auto_root && view->rdclass == dns_rdataclass_in) {
		const cfg_obj_t *builtin_keys = NULL;
		const cfg_obj_t *builtin_managed_keys = NULL;

		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
865
			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
			      "using built-in root key for view %s",
			      view->name);

		/*
		 * If bind.keys exists, it overrides the managed-keys
		 * clause hard-coded in ns_g_config.
		 */
		if (bindkeys != NULL) {
			(void)cfg_map_get(bindkeys, "trusted-keys",
					  &builtin_keys);
			(void)cfg_map_get(bindkeys, "managed-keys",
					  &builtin_managed_keys);
		} else {
			(void)cfg_map_get(ns_g_config, "trusted-keys",
					  &builtin_keys);
			(void)cfg_map_get(ns_g_config, "managed-keys",
					  &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));
	}

	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));

899
900
	if (view->rdclass == dns_rdataclass_in) {
		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
901
				     NULL, mctx));
902
		CHECK(load_view_keys(global_managed_keys, vconfig, view,
903
				     ISC_TRUE, NULL, mctx));
904
905
906
907
908
909
910
	}

	/*
	 * Add key zone for managed-keys.
	 */
	obj = NULL;
	(void)ns_config_get(maps, "managed-keys-directory", &obj);
911
912
913
914
915
916
917
918
919
920
921
	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
	if (directory != NULL)
		result = isc_file_isdirectory(directory);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "invalid managed-keys-directory %s: %s",
			      directory, isc_result_totext(result));
		goto cleanup;

	}
922
	CHECK(add_keydata_zone(view, directory, ns_g_mctx));
Automatic Updater's avatar
Automatic Updater committed
923

924
925
  cleanup:
	return (result);
926
}
927

928
static isc_result_t
929
mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
930
931
	const cfg_listelt_t *element;
	const cfg_obj_t *obj;
932
933
934
935
936
937
	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
938

939
940
941
942
943
944
945
946
	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"));
947
		isc_buffer_constinit(&b, str, strlen(str));
948
		isc_buffer_add(&b, strlen(str));
949
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
950
951
952
953
954
		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
955

956
957
958
 cleanup:
	return (result);
}
959

960
/*%
961
962
963
 * Get a dispatch appropriate for the resolver of a given view.
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
964
965
get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
966
			      isc_boolean_t is_firstview)
967
{
968
	isc_result_t result = ISC_R_FAILURE;
969
970
971
	dns_dispatch_t *disp;
	isc_sockaddr_t sa;
	unsigned int attrs, attrmask;
972
	const cfg_obj_t *obj = NULL;
973
	unsigned int maxdispatchbuffers = UDPBUFFERS;
Evan Hunt's avatar
Evan Hunt committed
974
	isc_dscp_t dscp = -1;
975
976
977

	switch (af) {
	case AF_INET:
978
979
		result = ns_config_get(maps, "query-source", &obj);
		INSIST(result == ISC_R_SUCCESS);
980
981
		break;
	case AF_INET6:
982
983
		result = ns_config_get(maps, "query-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
984
985
986
987
		break;
	default:
		INSIST(0);
	}
988

989
	sa = *(cfg_obj_assockaddr(obj));
990
991
	INSIST(isc_sockaddr_pf(&sa) == af);

Evan Hunt's avatar
Evan Hunt committed
992
993
994
995
	dscp = cfg_obj_getdscp(obj);
	if (dscp != -1 && dscpp != NULL)
		*dscpp = dscp;

996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
	/*
	 * If we don't support this address family, we're done!
	 */
	switch (af) {
	case AF_INET:
		result = isc_net_probeipv4();
		break;
	case AF_INET6:
		result = isc_net_probeipv6();
		break;
	default:
		INSIST(0);
	}
	if (result != ISC_R_SUCCESS)
		return (ISC_R_SUCCESS);

	/*
	 * Try to find a dispatcher that we can share.
	 */
	attrs = 0;
	attrs |= DNS_DISPATCHATTR_UDP;
	switch (af) {
	case AF_INET:
		attrs |= DNS_DISPATCHATTR_IPV4;
		break;
	case AF_INET6:
		attrs |= DNS_DISPATCHATTR_IPV6;
		break;
	}
1025
1026
	if (isc_sockaddr_getport(&sa) == 0) {
		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1027
		maxdispatchbuffers = EXCLBUFFERS;
1028
1029
1030
1031
1032
1033
1034
1035
1036
	} else {
		INSIST(obj != NULL);
		if (is_firstview) {
			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
				    "using specific query-source port "
				    "suppresses port randomization and can be "
				    "insecure.");
		}
	}
1037

1038
1039
1040
1041
1042
1043
1044
1045
1046
	attrmask = 0;
	attrmask |= DNS_DISPATCHATTR_UDP;
	attrmask |= DNS_DISPATCHATTR_TCP;
	attrmask |= DNS_DISPATCHATTR_IPV4;
	attrmask |= DNS_DISPATCHATTR_IPV6;

	disp = NULL;
	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
				     ns_g_taskmgr, &sa, 4096,
1047
				     maxdispatchbuffers, 32768, 16411, 16433,
1048
				     attrs, attrmask, &disp);
1049
	if (result != ISC_R_SUCCESS) {
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
		isc_sockaddr_t any;
		char buf[ISC_SOCKADDR_FORMATSIZE];

		switch (af) {
		case AF_INET:
			isc_sockaddr_any(&any);
			break;
		case AF_INET6:
			isc_sockaddr_any6(&any);
			break;
		}
		if (isc_sockaddr_equal(&sa, &any))
			return (ISC_R_SUCCESS);
		isc_sockaddr_format(&sa, buf, sizeof(buf));
1064
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1065
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1066
1067
			      "could not get query source dispatcher (%s)",
			      buf);
1068
		return (result);
1069
	}
1070
1071
1072
1073
1074
1075

	*dispatchp = disp;

	return (ISC_R_SUCCESS);
}

1076
static isc_result_t
1077
configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1078
1079
	dns_rdataclass_t rdclass;
	dns_rdatatype_t rdtype;
1080
	const cfg_obj_t *obj;
1081
1082
1083
1084
1085
	dns_fixedname_t fixed;
	unsigned int mode = 0;
	const char *str;
	isc_buffer_t b;
	isc_result_t result;
1086
	isc_boolean_t addroot;
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098

	result = ns_config_getclass(cfg_tuple_get(ent, "class"),
				    dns_rdataclass_any, &rdclass);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = ns_config_gettype(cfg_tuple_get(ent, "type"),
				   dns_rdatatype_any, &rdtype);
	if (result != ISC_R_SUCCESS)
		return (result);

	obj = cfg_tuple_get(ent, "name");
1099
	if (cfg_obj_isstring(obj))
1100
1101
1102
		str = cfg_obj_asstring(obj);
	else
		str = "*";
1103
	addroot = ISC_TF(strcmp(str, "*") == 0);
1104
	isc_buffer_constinit(&b, str, strlen(str));
1105
1106
1107
	isc_buffer_add(&b, strlen(str));
	dns_fixedname_init(&fixed);
	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,