server.c 273 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
 */

18
/*! \file */
David Lawrence's avatar
David Lawrence committed
19

20
21
22
#include <config.h>

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

29
#include <isc/app.h>
30
#include <isc/base64.h>
31
#include <isc/dir.h>
32
#include <isc/entropy.h>
33
#include <isc/file.h>
34
#include <isc/hash.h>
35
#include <isc/hex.h>
36
#include <isc/httpd.h>
37
#include <isc/lex.h>
38
#include <isc/parseint.h>
39
#include <isc/portset.h>
40
#include <isc/print.h>
41
#include <isc/random.h>
42
#include <isc/refcount.h>
43
#include <isc/resource.h>
44
#include <isc/sha2.h>
Mark Andrews's avatar
Mark Andrews committed
45
#include <isc/socket.h>
46
#include <isc/stat.h>
47
#include <isc/stats.h>
48
#include <isc/stdio.h>
49
#include <isc/string.h>
50
#include <isc/task.h>
51
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
52
#include <isc/util.h>
53
#include <isc/xml.h>
54

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

61
#include <isccfg/namedconf.h>
62
63

#include <bind9/check.h>
64

65
#include <dns/acache.h>
66
#include <dns/adb.h>
Evan Hunt's avatar
Evan Hunt committed
67
#include <dns/badcache.h>
68
#include <dns/cache.h>
69
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
70
#include <dns/dispatch.h>
71
#include <dns/dlz.h>
72
#include <dns/dns64.h>
73
#include <dns/forward.h>
74
#include <dns/journal.h>
75
#include <dns/keytable.h>
76
#include <dns/keyvalues.h>
77
#include <dns/lib.h>
78
#include <dns/master.h>
79
#include <dns/masterdump.h>
Evan Hunt's avatar
Evan Hunt committed
80
#include <dns/nta.h>
81
#include <dns/order.h>
82
#include <dns/peer.h>
83
#include <dns/portlist.h>
84
#include <dns/private.h>
85
#include <dns/rbt.h>
86
#include <dns/rdataclass.h>
87
#include <dns/rdatalist.h>
88
#include <dns/rdataset.h>
89
#include <dns/rdatastruct.h>
90
#include <dns/resolver.h>
91
#include <dns/rootns.h>
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>
Evan Hunt's avatar
Evan Hunt committed
97
#include <dns/ttl.h>
98
#include <dns/view.h>
99
#include <dns/zone.h>
100
#include <dns/zt.h>
101

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

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

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

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

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

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

155
156
157
#define TCHECK(op) \
	do { tresult = (op);					 \
		if (tresult != ISC_R_SUCCESS) {			 \
158
			isc_buffer_clear(*text);		 \
159
160
161
162
			goto cleanup;	 			 \
		}						 \
	} while (0)

163
#define CHECKM(op, msg) \
164
	do { result = (op);					  \
165
166
167
168
169
170
171
172
173
174
175
	       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
176
#define CHECKMF(op, msg, file) \
177
	do { result = (op);					  \
Mark Andrews's avatar
Mark Andrews committed
178
179
180
181
182
183
184
185
186
187
188
	       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)						  \

189
#define CHECKFATAL(op, msg) \
190
	do { result = (op);					  \
191
192
193
194
	       if (result != ISC_R_SUCCESS)			  \
			fatal(msg, result);			  \
	} while (0)						  \

195
196
197
198
199
200
/*%
 * 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
201
#define MAX_ADB_SIZE_FOR_CACHESHARE	8388608U
202

203
204
205
206
207
208
209
struct ns_dispatch {
	isc_sockaddr_t			addr;
	unsigned int			dispatchgen;
	dns_dispatch_t			*dispatch;
	ISC_LINK(struct ns_dispatch)	link;
};

210
211
212
213
214
215
216
217
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;
};

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
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;
};

244
245
/*%
 * Configuration context to retain for each view that allows
246
 * new zones to be added at runtime.
247
248
249
250
 */
struct cfg_context {
	isc_mem_t *			mctx;
	cfg_parser_t *			parser;
251
252
253
	cfg_obj_t *			config;
	cfg_parser_t *			nzparser;
	cfg_obj_t *			nzconfig;
254
	cfg_aclconfctx_t *		actx;
255
256
};

257
258
259
260
261
262
263
264
265
266
/*%
 * 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;

267
268
269
/*
 * These zones should not leak onto the Internet.
 */
270
const char *empty_zones[] = {
271
	/* RFC 1918 */
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
	"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",
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
348
349
350
351
352
353
354
355
356
	/* 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",

357
	/* RFC 5735 and RFC 5737 */
358
359
360
361
362
363
364
	"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 */
365
366

	/* Local IPv6 Unicast Addresses */
367
368
	"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
369
	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
370
371
372
373
374
	"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 */
375

376
	/* Example Prefix, RFC 3849. */
377
	"8.B.D.0.1.0.0.2.IP6.ARPA",
378

379
	NULL
380
381
};

Francis Dupont's avatar
Francis Dupont committed
382
383
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
384
385
386

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

388
static isc_result_t
389
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
390
391
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			isc_uint16_t family, ns_listenelt_t **target);
392
static isc_result_t
393
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
394
395
			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			 isc_uint16_t family, ns_listenlist_t **target);
396

397
static isc_result_t
398
399
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);
400

401
static isc_result_t
402
403
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
404

405
static isc_result_t
406
407
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
408
409
	       dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
	       isc_boolean_t added, isc_boolean_t old_rpz_ok);
410

411
static isc_result_t
412
add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
413

414
415
416
static void
end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);

417
static void
418
newzone_cfgctx_destroy(void **cfgp);
419

Mark Andrews's avatar
Mark Andrews committed
420
static inline isc_result_t
421
putstr(isc_buffer_t **b, const char *str);
422

423
static isc_result_t
424
425
426
427
428
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
429
static inline isc_result_t
430
putnull(isc_buffer_t **b);
431

Evan Hunt's avatar
Evan Hunt committed
432
433
434
isc_result_t
add_comment(FILE *fp, const char *viewname);

435
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
436
437
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
438
439
 */
static isc_result_t
440
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
441
442
		   const char *aclname, const char *acltuplename,
		   cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
443
444
{
	isc_result_t result;
445
446
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
447
448
	int i = 0;

449
450
	if (*aclp != NULL)
		dns_acl_detach(aclp);
451
452
453
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
454
		const cfg_obj_t *options = NULL;
455
		(void)cfg_map_get(config, "options", &options);
456
457
458
459
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i] = NULL;
460

461
	(void)ns_config_get(maps, aclname, &aclobj);
462
	if (aclobj == NULL)
463
		/*
464
		 * No value available.	*aclp == NULL.
465
		 */
466
467
		return (ISC_R_SUCCESS);

468
469
470
471
472
473
474
475
476
	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);
	}

477
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
478
479
480
481
482
483
484
485
486
487
488
489
				    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
490
491
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
{
	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
514
515
516
517
518
519
	/*
	 * 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.
	 */
520
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
521
				    actx, mctx, 3, aclp);
522
523
524
525

	return (result);
}

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
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
static isc_result_t
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
			 const char *confname, const char *conftuplename,
			 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);
578
		isc_buffer_constinit(&b, str, strlen(str));
579
		isc_buffer_add(&b, strlen(str));
580
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
581
582
583
584
585
586
587
		/*
		 * 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.
		 */
588
589
590
591
592
593
594
		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
595

596
597
598
599
600
601
602
	}

	return (result);

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

604
605
}

606
static isc_result_t
607
608
dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
609
610
{
	dns_rdataclass_t viewclass;
611
	dns_rdata_dnskey_t keystruct;
612
	isc_uint32_t flags, proto, alg;
613
	const char *keystr, *keynamestr;
614
615
616
617
618
619
620
621
622
623
624
	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;

625
626
	INSIST(target != NULL && *target == NULL);

627
628
629
630
631
632
	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
633
634
635
636
	if (managed) {
		const char *initmethod;
		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));

637
		if (strcasecmp(initmethod, "initial-key") != 0) {
Automatic Updater's avatar
Automatic Updater committed
638
639
640
641
642
643
644
645
			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;
		}
	}
646

647
	if (vconfig == NULL)
648
		viewclass = dns_rdataclass_in;
649
	else {
650
		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
651
652
		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
					 &viewclass));
653
	}
654
	keystruct.common.rdclass = viewclass;
655
	keystruct.common.rdtype = dns_rdatatype_dnskey;
656
	/*
657
	 * The key data in keystruct is not dynamically allocated.
658
659
660
661
662
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

663
	if (flags > 0xffff)
664
		CHECKM(ISC_R_RANGE, "key flags");
665
	if (proto > 0xff)
666
		CHECKM(ISC_R_RANGE, "key protocol");
667
	if (alg > 0xff)
668
		CHECKM(ISC_R_RANGE, "key algorithm");
669
670
671
	keystruct.flags = (isc_uint16_t)flags;
	keystruct.protocol = (isc_uint8_t)proto;
	keystruct.algorithm = (isc_uint8_t)alg;
672
673
674
675

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

676
	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
677
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
678
679
680
681
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

682
683
684
685
	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,
686
687
			    "%s key '%s' has a weak exponent",
			    managed ? "managed" : "trusted",
688
689
			    keynamestr);

690
691
692
693
694
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
695
	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
696
	isc_buffer_add(&namebuf, strlen(keynamestr));
697
	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
698
699
700
	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
			      mctx, &dstkey));

701
	*target = dstkey;
702
703
704
	return (ISC_R_SUCCESS);

 cleanup:
705
706
	if (result == DST_R_NOCRYPTO) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
707
708
			    "ignoring %s key for '%s': no crypto support",
			    managed ? "managed" : "trusted",
709
			    keynamestr);
710
711
712
713
714
	} 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));
715
716
	} else {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
717
718
			    "configuring %s key for '%s': %s",
			    managed ? "managed" : "trusted",
719
720
721
			    keynamestr, isc_result_totext(result));
		result = ISC_R_FAILURE;
	}
722
723
724
725
726
727
728

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

	return (result);
}

729
730
static isc_result_t
load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
731
732
	       dns_view_t *view, isc_boolean_t managed,
	       dns_name_t *keyname, isc_mem_t *mctx)
733
734
{
	const cfg_listelt_t *elt, *elt2;
735
736
	const cfg_obj_t *key, *keylist;
	dst_key_t *dstkey = NULL;
737
738
739
740
	isc_result_t result;
	dns_keytable_t *secroots = NULL;

	CHECK(dns_view_getsecroots(view, &secroots));
741
742
743
744
745
746
747
748
749
750

	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);
751
752
753
754
755
756
757
758
			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;
759

760
761
762
763
			/*
			 * If keyname was specified, we only add that key.
			 */
			if (keyname != NULL &&
Automatic Updater's avatar
Automatic Updater committed
764
			    !dns_name_equal(keyname, dst_key_name(dstkey)))
765
766
767
768
769
			{
				dst_key_free(&dstkey);
				continue;
			}

770
			CHECK(dns_keytable_add(secroots, managed, &dstkey));
771
772
773
774
		}
	}

 cleanup:
775
776
	if (dstkey != NULL)
		dst_key_free(&dstkey);
777
778
	if (secroots != NULL)
		dns_keytable_detach(&secroots);
779
780
	if (result == DST_R_NOCRYPTO)
		result = ISC_R_SUCCESS;
781
	return (result);
782
783
}

784
/*%
785
 * Configure DNSSEC keys for a view.
786
 *
787
 * The per-view configuration values and the server-global defaults are read
788
 * from 'vconfig' and 'config'.
789
790
 */
static isc_result_t
791
792
configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
793
794
			  isc_boolean_t auto_dlv, isc_boolean_t auto_root,
			  isc_mem_t *mctx)
795
{
796
	isc_result_t result = ISC_R_SUCCESS;
797
798
	const cfg_obj_t *view_keys = NULL;
	const cfg_obj_t *global_keys = NULL;
799
	const cfg_obj_t *view_managed_keys = NULL;
800
	const cfg_obj_t *global_managed_keys = NULL;
801
	const cfg_obj_t *maps[4];
802
	const cfg_obj_t *voptions = NULL;
803
	const cfg_obj_t *options = NULL;
804
805
	const cfg_obj_t *obj = NULL;
	const char *directory;
806
	int i = 0;
807

808
	/* We don't need trust anchors for the _bind view */
809
810
	if (strcmp(view->name, "_bind") == 0 &&
	    view->rdclass == dns_rdataclass_chaos) {
811
812
		return (ISC_R_SUCCESS);
	}
813

814
	if (vconfig != NULL) {
815
		voptions = cfg_tuple_get(vconfig, "options");
816
		if (voptions != NULL) {
817
818
			(void) cfg_map_get(voptions, "trusted-keys",
					   &view_keys);
819
820
			(void) cfg_map_get(voptions, "managed-keys",
					   &view_managed_keys);
821
822
823
			maps[i++] = voptions;
		}
	}
824

825
826
	if (config != NULL) {
		(void)cfg_map_get(config, "trusted-keys", &global_keys);
827
		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
828
829
830
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL) {
			maps[i++] = options;
831
		}
832
	}
833

834
835
836
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

837
	result = dns_view_initsecroots(view, mctx);
838
839
840
841
842
843
844
	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);
	}

Evan Hunt's avatar
Evan Hunt committed
845
	result = dns_view_initntatable(view, ns_g_taskmgr, ns_g_timermgr);
Evan Hunt's avatar
Evan Hunt committed
846
847
848
849
850
851
852
	if (result != ISC_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "couldn't create NTA table");
		return (ISC_R_UNEXPECTED);
	}

853
	if (auto_dlv && view->rdclass == dns_rdataclass_in) {
854
855
856
		const cfg_obj_t *builtin_keys = NULL;
		const cfg_obj_t *builtin_managed_keys = NULL;

857
		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
858
			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
859
			      "using built-in DLV key for view %s",
860
			      view->name);
861
862

		/*
863
		 * If bind.keys exists, it overrides the managed-keys
864
865
		 * clause hard-coded in ns_g_config.
		 */
866
		if (bindkeys != NULL) {
867
868
			(void)cfg_map_get(bindkeys, "trusted-keys",
					  &builtin_keys);
869
870
871
			(void)cfg_map_get(bindkeys, "managed-keys",
					  &builtin_managed_keys);
		} else {
872
873
			(void)cfg_map_get(ns_g_config, "trusted-keys",
					  &builtin_keys);
874
875
876
877
			(void)cfg_map_get(ns_g_config, "managed-keys",
					  &builtin_managed_keys);
		}

878
879
		if (builtin_keys != NULL)
			CHECK(load_view_keys(builtin_keys, vconfig, view,
880
					     ISC_FALSE, view->dlv, mctx));
881
882
		if (builtin_managed_keys != NULL)
			CHECK(load_view_keys(builtin_managed_keys, vconfig,
883
					     view, ISC_TRUE, view->dlv, mctx));
884
885
	}

886
887
888
889
890
	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,
891
			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
			      "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));

925
926
	if (view->rdclass == dns_rdataclass_in) {
		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
927
				     NULL, mctx));
928
		CHECK(load_view_keys(global_managed_keys, vconfig, view,
929
				     ISC_TRUE, NULL, mctx));
930
931
932
933
934
935
936
	}

	/*
	 * Add key zone for managed-keys.
	 */
	obj = NULL;
	(void)ns_config_get(maps, "managed-keys-directory", &obj);
937
938
939
940
941
942
943
944
945
946
947
	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;

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

950
951
  cleanup:
	return (result);
952
}
953

954
static isc_result_t
955
mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
956
957
	const cfg_listelt_t *element;
	const cfg_obj_t *obj;
958
959
960
961
962
963
	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
964

965
966
967
968
969
970
971
972
	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"));
973
		isc_buffer_constinit(&b, str, strlen(str));
974
		isc_buffer_add(&b, strlen(str));
975
		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
976
977
978
979
980
		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
981

982
983
984
 cleanup:
	return (result);
}
985

986
/*%
987
988
989
 * Get a dispatch appropriate for the resolver of a given view.
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
990
991
get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
992
			      isc_boolean_t is_firstview)
993
{
994
	isc_result_t result = ISC_R_FAILURE;
995
996
997
	dns_dispatch_t *disp;
	isc_sockaddr_t sa;
	unsigned int attrs, attrmask;
998
	const cfg_obj_t *obj = NULL;
999
	unsigned int maxdispatchbuffers = UDPBUFFERS;
Evan Hunt's avatar
Evan Hunt committed
1000
	isc_dscp_t dscp = -1;
1001
1002
1003

	switch (af) {
	case AF_INET:
1004
1005
		result = ns_config_get(maps, "query-source", &obj);
		INSIST(result == ISC_R_SUCCESS);
1006
1007
		break;
	case AF_INET6:
1008
1009
		result = ns_config_get(maps, "query-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
1010
1011
1012
1013
		break;
	default:
		INSIST(0);
	}
1014

1015
	sa = *(cfg_obj_assockaddr(obj));
1016
1017
	INSIST(isc_sockaddr_pf(&sa) == af);

Evan Hunt's avatar
Evan Hunt committed
1018
1019
1020
1021
	dscp = cfg_obj_getdscp(obj);
	if (dscp != -1 && dscpp != NULL)
		*dscpp = dscp;

1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
	/*
	 * 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;
	}
1051
1052
	if (isc_sockaddr_getport(&sa) == 0) {
		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1053
		maxdispatchbuffers = EXCLBUFFERS;
1054
1055
1056
1057
1058
1059
1060
1061
1062
	} 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.");
		}
	}
1063

1064
1065
1066
1067
1068
1069
1070
1071
1072
	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,
1073
				     maxdispatchbuffers, 32768, 16411, 16433,
1074
				     attrs, attrmask, &disp);
1075
	if (result != ISC_R_SUCCESS) {
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
		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));
1090
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1091
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1092
1093
			      "could not get query source dispatcher (%s)",
			      buf);
1094
		return (result);
1095
	}
1096
1097
1098
1099
1100
1101

	*dispatchp = disp;

	return (ISC_R_SUCCESS);
}

1102
static isc_result_t
1103
configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1104
1105
	dns_rdataclass_t rdclass;
	dns_rdatatype_t rdtype;
1106
	const cfg_obj_t *obj;
1107
1108
1109
1110
1111
	dns_fixedname_t fixed;
	unsigned int mode = 0;
	const char *str;
	isc_buffer_t b;
	isc_result_t result;
1112
	isc_boolean_t addroot;
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124

	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");
1125
	if (cfg_obj_isstring(obj))
1126
1127
1128
		str = cfg_obj_asstring(obj);
	else
		str = "*";
1129
	addroot = ISC_TF(strcmp(str, "*") == 0);
1130
	isc_buffer_constinit(&b, str, strlen(str));
1131
1132
1133
	isc_buffer_add(&b, strlen(str));
	dns_fixedname_init(&fixed);
	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1134
				   dns_rootname, 0, NULL);
1135
1136
1137
1138
1139
1140
1141
	if (result != ISC_R_SUCCESS)
		return (result);

	obj = cfg_tuple_get(ent, "ordering");
	INSIST(cfg_obj_isstring(obj));
	str = cfg_obj_asstring(obj);
	if (!strcasecmp(str, "fixed"))
Evan Hunt's avatar
Evan Hunt committed
1142
#if DNS_RDATASET_FIXED
1143
		mode = DNS_RDATASETATTR_FIXEDORDER;
Evan Hunt's avatar
Evan Hunt committed
1144
1145
1146
#else
		mode = 0;
#endif /* DNS_RDATASET_FIXED */
1147
1148
1149
1150
1151
1152
1153
	else if (!strcasecmp(str, "random"))
		mode = DNS_RDATASETATTR_RANDOMIZE;
	else if (!strcasecmp(str, "cyclic"))
		mode = 0;
	else
		INSIST(0);

1154
1155
1156
	/*
	 * "*" should match everything including the root (BIND 8 compat).
	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
Mark Andrews's avatar
Mark Andrews committed
1157
	 * explicit entry for "." when the name is "*".
1158
1159
1160
1161
1162
1163
1164
1165
	 */
	if (addroot) {
		result = dns_order_add(order, dns_rootname,
				       rdtype, rdclass, mode);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

1166
1167
1168
1169
	return (dns_order_add(order, dns_fixedname_name(&fixed),
			      rdtype, rdclass, mode));
}

1170
static isc_result_t
1171
configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1172
1173
	isc_netaddr_t na;
	dns_peer_t *peer;
1174
	const cfg_obj_t *obj;
1175
	const char *str;
1176
	isc_result_t result;
1177
	unsigned int prefixlen;
1178

1179
	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1180
1181

	peer = NULL;
1182
	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1183
1184
1185
1186
1187
1188
	if (result != ISC_R_SUCCESS)
		return (result);

	obj = NULL;
	(void)cfg_map_get(cpeer, "bogus", &obj);
	if (obj != NULL)
1189
		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1190
1191
1192
1193

	obj = NULL;
	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
	if (obj != NULL)
1194
		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1195

1196
1197
1198
1199
1200
	obj = NULL;
	(void)cfg_map_get(cpeer, "request-expire", &obj);
	if (obj != NULL)
		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));

1201
1202
1203
	obj = NULL;
	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
	if (obj != NULL)
1204
		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1205

1206
1207
1208
1209
1210
	obj = NULL;
	(void)cfg_map_get(cpeer, "request-nsid", &obj);
	if (obj != NULL)
		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));

1211
1212
1213
1214
1215
1216
1217
#ifdef ISC_PLATFORM_USESIT
	obj = NULL;
	(void)cfg_map_get(cpeer, "request-sit", &obj);
	if (obj != NULL)
		CHECK(dns_peer_setrequestsit(peer, cfg_obj_asboolean(obj)));
#endif

1218
1219
1220
	obj = NULL;
	(void)cfg_map_get(cpeer, "edns", &obj);
	if (obj != NULL)
1221
		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1222

1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
	obj = NULL;
	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
	if (obj != NULL) {
		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
		if (udpsize < 512)
			udpsize = 512;
		if (udpsize > 4096)
			udpsize = 4096;
		CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
	}

1234
1235
1236
1237
1238
1239
1240
1241
1242
	obj = NULL;
	(void)cfg_map_get(cpeer, "edns-version", &obj);
	if (obj != NULL) {
		isc_uint32_t ednsversion = cfg_obj_asuint32(obj);
		if (ednsversion > 255)
			ednsversion = 255;
		CHECK(dns_peer_setednsversion(peer, (isc_uint8_t)ednsversion));
	}

1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
	obj = NULL;
	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
	if (obj != NULL) {
		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
		if (udpsize < 512)
			udpsize = 512;
		if (udpsize > 4096)
			udpsize = 4096;
		CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
	}

1254
1255
1256
	obj = NULL;
	(void)cfg_map_get(cpeer, "transfers", &obj);
	if (obj != NULL)
1257
		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1258
1259
1260
1261
1262
1263

	obj = NULL;
	(void)cfg_map_get(cpeer, "transfer-format", &obj);
	if (obj != NULL) {
		str = cfg_obj_asstring(obj);
		if (strcasecmp(str, "many-answers") == 0)
1264
1265
			CHECK(dns_peer_settransferformat(peer,
							 dns_many_answers));
1266
		else if (strcasecmp(str, "one-answer") == 0)
1267
1268
			CHECK(dns_peer_settransferformat(peer,
							 dns_one_answer));
1269
1270
1271
1272
1273