server.c 147 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2008  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
 */

Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
18
/* $Id: server.c,v 1.521 2008/12/25 02:00:49 jinmei Exp $ */
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

27
#include <isc/app.h>
28
#include <isc/base64.h>
29
#include <isc/dir.h>
30
#include <isc/entropy.h>
31
#include <isc/file.h>
32
#include <isc/hash.h>
33
#include <isc/httpd.h>
34
#include <isc/lex.h>
35
#include <isc/parseint.h>
36
#include <isc/portset.h>
37 38
#include <isc/print.h>
#include <isc/resource.h>
Mark Andrews's avatar
Mark Andrews committed
39
#include <isc/socket.h>
40
#include <isc/stdio.h>
41
#include <isc/string.h>
42
#include <isc/task.h>
43
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
44
#include <isc/util.h>
45
#include <isc/xml.h>
46

47
#include <isccfg/namedconf.h>
48 49

#include <bind9/check.h>
50

51
#include <dns/acache.h>
52
#include <dns/adb.h>
53
#include <dns/cache.h>
54
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
55
#include <dns/dispatch.h>
56 57 58
#ifdef DLZ
#include <dns/dlz.h>
#endif
59
#include <dns/forward.h>
60
#include <dns/journal.h>
61
#include <dns/keytable.h>
62
#include <dns/lib.h>
63
#include <dns/master.h>
64
#include <dns/masterdump.h>
65
#include <dns/order.h>
66
#include <dns/peer.h>
67
#include <dns/portlist.h>
68
#include <dns/rbt.h>
69
#include <dns/rdataclass.h>
70
#include <dns/rdataset.h>
71
#include <dns/rdatastruct.h>
72
#include <dns/resolver.h>
73
#include <dns/rootns.h>
74
#include <dns/secalg.h>
75
#include <dns/stats.h>
76
#include <dns/tkey.h>
77
#include <dns/tsig.h>
78
#include <dns/view.h>
79
#include <dns/zone.h>
80
#include <dns/zt.h>
81

82
#include <dst/dst.h>
83
#include <dst/result.h>
84

85
#include <named/client.h>
86
#include <named/config.h>
87
#include <named/control.h>
88
#include <named/interfacemgr.h>
89
#include <named/log.h>
90
#include <named/logconf.h>
91
#include <named/lwresd.h>
92
#include <named/main.h>
93
#include <named/os.h>
Bob Halley's avatar
Bob Halley committed
94
#include <named/server.h>
95
#include <named/statschannel.h>
96 97 98
#include <named/tkeyconf.h>
#include <named/tsigconf.h>
#include <named/zoneconf.h>
99 100 101 102
#ifdef HAVE_LIBSCF
#include <named/ns_smf_globals.h>
#include <stdlib.h>
#endif
103

104
/*%
105 106 107 108
 * Check an operation for failure.  Assumes that the function
 * using it has a 'result' variable and a 'cleanup' label.
 */
#define CHECK(op) \
109 110
	do { result = (op);					 \
	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
111 112 113
	} while (0)

#define CHECKM(op, msg) \
114
	do { result = (op);					  \
115 116 117 118 119 120 121 122 123 124 125
	       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
126
#define CHECKMF(op, msg, file) \
127
	do { result = (op);					  \
Mark Andrews's avatar
Mark Andrews committed
128 129 130 131 132 133 134 135 136 137 138
	       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)						  \

139
#define CHECKFATAL(op, msg) \
140
	do { result = (op);					  \
141 142 143 144
	       if (result != ISC_R_SUCCESS)			  \
			fatal(msg, result);			  \
	} while (0)						  \

145 146 147 148 149 150 151
struct ns_dispatch {
	isc_sockaddr_t			addr;
	unsigned int			dispatchgen;
	dns_dispatch_t			*dispatch;
	ISC_LINK(struct ns_dispatch)	link;
};

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
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;
};

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/*
 * These zones should not leak onto the Internet.
 */
static const struct {
	const char	*zone;
	isc_boolean_t	rfc1918;
} empty_zones[] = {
#ifdef notyet
	/* RFC 1918 */
	{ "10.IN-ADDR.ARPA", ISC_TRUE },
	{ "16.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "17.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "18.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "19.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "20.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "21.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "22.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "23.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "24.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "25.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "26.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "27.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "28.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "29.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "30.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "31.172.IN-ADDR.ARPA", ISC_TRUE },
	{ "168.192.IN-ADDR.ARPA", ISC_TRUE },
#endif

	/* RFC 3330 */
208
	{ "0.IN-ADDR.ARPA", ISC_FALSE },	/* THIS NETWORK */
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
	{ "127.IN-ADDR.ARPA", ISC_FALSE },	/* LOOPBACK */
	{ "254.169.IN-ADDR.ARPA", ISC_FALSE },	/* LINK LOCAL */
	{ "2.0.192.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET */
	{ "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE },	/* BROADCAST */

	/* Local IPv6 Unicast Addresses */
	{ "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", ISC_FALSE },
	{ "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", ISC_FALSE },
	/* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */
	{ "D.F.IP6.ARPA", ISC_FALSE },
	{ "8.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
	{ "9.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
	{ "A.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
	{ "B.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */

	{ NULL, ISC_FALSE }
};

David Lawrence's avatar
David Lawrence committed
227 228 229 230 231
static void
fatal(const char *msg, isc_result_t result);

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

233
static isc_result_t
234
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
235
			cfg_aclconfctx_t *actx,
236 237
			isc_mem_t *mctx, ns_listenelt_t **target);
static isc_result_t
238
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
239
			 cfg_aclconfctx_t *actx,
240
			 isc_mem_t *mctx, ns_listenlist_t **target);
241

242
static isc_result_t
243 244
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);
245

246
static isc_result_t
247 248
configure_alternates(const cfg_obj_t *config, dns_view_t *view,
		     const cfg_obj_t *alternates);
249

250
static isc_result_t
251 252
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,
253
	       cfg_aclconfctx_t *aclconf);
254

255 256 257
static void
end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);

258
/*%
259
 * Configure a single view ACL at '*aclp'.  Get its configuration by
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
260 261
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
262 263
 */
static isc_result_t
264
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
265
		   const char *aclname, cfg_aclconfctx_t *actx,
266
		   isc_mem_t *mctx, dns_acl_t **aclp)
267 268
{
	isc_result_t result;
269 270
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
271 272
	int i = 0;

273 274
	if (*aclp != NULL)
		dns_acl_detach(aclp);
275 276 277
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
278
		const cfg_obj_t *options = NULL;
279
		(void)cfg_map_get(config, "options", &options);
280 281 282 283
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i] = NULL;
284

285
	(void)ns_config_get(maps, aclname, &aclobj);
286
	if (aclobj == NULL)
287
		/*
288
		 * No value available.	*aclp == NULL.
289
		 */
290 291
		return (ISC_R_SUCCESS);

292
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
293 294 295 296 297 298 299 300 301 302 303 304 305
				    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
306 307
			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
			dns_acl_t **aclp)
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
{
	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
330 331 332 333 334 335
	/*
	 * 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.
	 */
336
	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
337
				    actx, mctx, 3, aclp);
338 339 340 341

	return (result);
}

342
static isc_result_t
343
configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key,
344 345 346
			 dns_keytable_t *keytable, isc_mem_t *mctx)
{
	dns_rdataclass_t viewclass;
347
	dns_rdata_dnskey_t keystruct;
348
	isc_uint32_t flags, proto, alg;
349
	const char *keystr, *keynamestr;
350 351 352 353 354 355 356 357 358 359 360
	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;

361 362 363 364 365 366 367
	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"));

	if (vconfig == NULL)
368
		viewclass = dns_rdataclass_in;
369
	else {
370
		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
371 372
		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
					 &viewclass));
373
	}
374
	keystruct.common.rdclass = viewclass;
375
	keystruct.common.rdtype = dns_rdatatype_dnskey;
376
	/*
377
	 * The key data in keystruct is not dynamically allocated.
378 379 380 381 382
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

383
	if (flags > 0xffff)
384
		CHECKM(ISC_R_RANGE, "key flags");
385
	if (proto > 0xff)
386
		CHECKM(ISC_R_RANGE, "key protocol");
387
	if (alg > 0xff)
388
		CHECKM(ISC_R_RANGE, "key algorithm");
389 390 391
	keystruct.flags = (isc_uint16_t)flags;
	keystruct.protocol = (isc_uint8_t)proto;
	keystruct.algorithm = (isc_uint8_t)alg;
392 393 394 395

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

396
	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
397
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
398 399 400 401
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

402 403 404 405 406 407 408
	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,
			    "trusted key '%s' has a weak exponent",
			    keynamestr);

409 410 411 412 413
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
414 415
	isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
	isc_buffer_add(&namebuf, strlen(keynamestr));
416 417 418 419 420 421 422 423 424 425 426
	CHECK(dns_name_fromtext(keyname, &namebuf,
				dns_rootname, ISC_FALSE,
				NULL));
	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
			      mctx, &dstkey));

	CHECK(dns_keytable_add(keytable, &dstkey));
	INSIST(dstkey == NULL);
	return (ISC_R_SUCCESS);

 cleanup:
427 428 429 430 431 432 433 434 435 436 437
	if (result == DST_R_NOCRYPTO) {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
			    "ignoring trusted key for '%s': no crypto support",
			    keynamestr);
		result = ISC_R_SUCCESS;
	} else {
		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
			    "configuring trusted key for '%s': %s",
			    keynamestr, isc_result_totext(result));
		result = ISC_R_FAILURE;
	}
438 439 440 441 442 443 444

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

	return (result);
}

445
/*%
446 447
 * Configure DNSSEC keys for a view.  Currently used only for
 * the security roots.
448
 *
449
 * The per-view configuration values and the server-global defaults are read
450
 * from 'vconfig' and 'config'.	 The variable to be configured is '*target'.
451 452
 */
static isc_result_t
453
configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config,
454
			  isc_mem_t *mctx, dns_keytable_t **target)
455 456
{
	isc_result_t result;
457 458 459 460 461
	const cfg_obj_t *keys = NULL;
	const cfg_obj_t *voptions = NULL;
	const cfg_listelt_t *element, *element2;
	const cfg_obj_t *keylist;
	const cfg_obj_t *key;
462
	dns_keytable_t *keytable = NULL;
463

464 465
	CHECK(dns_keytable_create(mctx, &keytable));

466 467
	if (vconfig != NULL)
		voptions = cfg_tuple_get(vconfig, "options");
468

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
	keys = NULL;
	if (voptions != NULL)
		(void)cfg_map_get(voptions, "trusted-keys", &keys);
	if (keys == NULL)
		(void)cfg_map_get(config, "trusted-keys", &keys);

	for (element = cfg_list_first(keys);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		keylist = cfg_listelt_value(element);
		for (element2 = cfg_list_first(keylist);
		     element2 != NULL;
		     element2 = cfg_list_next(element2))
		{
			key = cfg_listelt_value(element2);
			CHECK(configure_view_dnsseckey(vconfig, key,
486
						       keytable, mctx));
487
		}
488
	}
489

490 491 492 493
	dns_keytable_detach(target);
	*target = keytable; /* Transfer ownership. */
	keytable = NULL;
	result = ISC_R_SUCCESS;
Automatic Updater's avatar
Automatic Updater committed
494

495 496 497
 cleanup:
	return (result);
}
498

499
static isc_result_t
500
mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver)
501
{
502 503
	const cfg_listelt_t *element;
	const cfg_obj_t *obj;
504 505 506 507 508 509
	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
510

511 512 513 514 515 516 517 518 519 520 521
	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"));
		isc_buffer_init(&b, str, strlen(str));
		isc_buffer_add(&b, strlen(str));
		CHECK(dns_name_fromtext(name, &b, dns_rootname,
522
					ISC_FALSE, NULL));
523 524 525 526 527
		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
528

529 530 531
 cleanup:
	return (result);
}
532

533
/*%
534 535 536
 * Get a dispatch appropriate for the resolver of a given view.
 */
static isc_result_t
537
get_view_querysource_dispatch(const cfg_obj_t **maps,
538 539
			      int af, dns_dispatch_t **dispatchp,
			      isc_boolean_t is_firstview)
540 541 542 543 544
{
	isc_result_t result;
	dns_dispatch_t *disp;
	isc_sockaddr_t sa;
	unsigned int attrs, attrmask;
545
	const cfg_obj_t *obj = NULL;
546
	unsigned int maxdispatchbuffers;
547 548 549 550 551 552 553 554

	/*
	 * Make compiler happy.
	 */
	result = ISC_R_FAILURE;

	switch (af) {
	case AF_INET:
555 556
		result = ns_config_get(maps, "query-source", &obj);
		INSIST(result == ISC_R_SUCCESS);
557 558
		break;
	case AF_INET6:
559 560
		result = ns_config_get(maps, "query-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
561 562 563 564
		break;
	default:
		INSIST(0);
	}
565

566
	sa = *(cfg_obj_assockaddr(obj));
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
	INSIST(isc_sockaddr_pf(&sa) == af);

	/*
	 * 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;
	}
598 599 600 601 602 603 604 605 606 607 608 609 610
	if (isc_sockaddr_getport(&sa) == 0) {
		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
		maxdispatchbuffers = 4096;
	} 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.");
		}
		maxdispatchbuffers = 1000;
	}
611

612 613 614 615 616 617 618 619 620
	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,
621
				     maxdispatchbuffers, 32768, 16411, 16433,
622
				     attrs, attrmask, &disp);
623
	if (result != ISC_R_SUCCESS) {
624 625 626 627 628 629 630 631 632 633 634 635 636 637
		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));
638
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
639
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
640 641
			      "could not get query source dispatcher (%s)",
			      buf);
642
		return (result);
643
	}
644 645 646 647 648 649

	*dispatchp = disp;

	return (ISC_R_SUCCESS);
}

650
static isc_result_t
651
configure_order(dns_order_t *order, const cfg_obj_t *ent) {
652 653
	dns_rdataclass_t rdclass;
	dns_rdatatype_t rdtype;
654
	const cfg_obj_t *obj;
655 656 657 658 659
	dns_fixedname_t fixed;
	unsigned int mode = 0;
	const char *str;
	isc_buffer_t b;
	isc_result_t result;
660
	isc_boolean_t addroot;
661 662 663 664 665 666 667 668 669 670 671 672

	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");
673
	if (cfg_obj_isstring(obj))
674 675 676
		str = cfg_obj_asstring(obj);
	else
		str = "*";
677
	addroot = ISC_TF(strcmp(str, "*") == 0);
678 679 680 681
	isc_buffer_init(&b, str, strlen(str));
	isc_buffer_add(&b, strlen(str));
	dns_fixedname_init(&fixed);
	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
682
				   dns_rootname, ISC_FALSE, NULL);
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
	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"))
		mode = DNS_RDATASETATTR_FIXEDORDER;
	else if (!strcasecmp(str, "random"))
		mode = DNS_RDATASETATTR_RANDOMIZE;
	else if (!strcasecmp(str, "cyclic"))
		mode = 0;
	else
		INSIST(0);

698 699 700
	/*
	 * "*" should match everything including the root (BIND 8 compat).
	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
Mark Andrews's avatar
Mark Andrews committed
701
	 * explicit entry for "." when the name is "*".
702 703 704 705 706 707 708 709
	 */
	if (addroot) {
		result = dns_order_add(order, dns_rootname,
				       rdtype, rdclass, mode);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

710 711 712 713
	return (dns_order_add(order, dns_fixedname_name(&fixed),
			      rdtype, rdclass, mode));
}

714
static isc_result_t
715
configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
716 717
	isc_netaddr_t na;
	dns_peer_t *peer;
718
	const cfg_obj_t *obj;
719
	const char *str;
720
	isc_result_t result;
721
	unsigned int prefixlen;
722

723
	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
724 725

	peer = NULL;
726
	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
727 728 729 730 731 732
	if (result != ISC_R_SUCCESS)
		return (result);

	obj = NULL;
	(void)cfg_map_get(cpeer, "bogus", &obj);
	if (obj != NULL)
733
		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
734 735 736 737

	obj = NULL;
	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
	if (obj != NULL)
738
		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
739 740 741 742

	obj = NULL;
	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
	if (obj != NULL)
743
		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
744

745 746 747 748 749
	obj = NULL;
	(void)cfg_map_get(cpeer, "request-nsid", &obj);
	if (obj != NULL)
		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));

750 751 752
	obj = NULL;
	(void)cfg_map_get(cpeer, "edns", &obj);
	if (obj != NULL)
753
		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
754

755 756 757 758 759 760 761 762 763 764 765
	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));
	}

766 767 768 769 770 771 772 773 774 775 776
	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));
	}

777 778 779
	obj = NULL;
	(void)cfg_map_get(cpeer, "transfers", &obj);
	if (obj != NULL)
780
		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
781 782 783 784 785 786

	obj = NULL;
	(void)cfg_map_get(cpeer, "transfer-format", &obj);
	if (obj != NULL) {
		str = cfg_obj_asstring(obj);
		if (strcasecmp(str, "many-answers") == 0)
787 788
			CHECK(dns_peer_settransferformat(peer,
							 dns_many_answers));
789
		else if (strcasecmp(str, "one-answer") == 0)
790 791
			CHECK(dns_peer_settransferformat(peer,
							 dns_one_answer));
792 793 794 795 796 797 798 799 800 801 802
		else
			INSIST(0);
	}

	obj = NULL;
	(void)cfg_map_get(cpeer, "keys", &obj);
	if (obj != NULL) {
		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
		if (result != ISC_R_SUCCESS)
			goto cleanup;
	}
803 804

	obj = NULL;
805
	if (na.family == AF_INET)
806 807 808 809 810 811 812 813
		(void)cfg_map_get(cpeer, "transfer-source", &obj);
	else
		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
	if (obj != NULL) {
		result = dns_peer_settransfersource(peer,
						    cfg_obj_assockaddr(obj));
		if (result != ISC_R_SUCCESS)
			goto cleanup;
814
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
815
	}
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842

	obj = NULL;
	if (na.family == AF_INET)
		(void)cfg_map_get(cpeer, "notify-source", &obj);
	else
		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
	if (obj != NULL) {
		result = dns_peer_setnotifysource(peer,
						  cfg_obj_assockaddr(obj));
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
	}

	obj = NULL;
	if (na.family == AF_INET)
		(void)cfg_map_get(cpeer, "query-source", &obj);
	else
		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
	if (obj != NULL) {
		result = dns_peer_setquerysource(peer,
						 cfg_obj_assockaddr(obj));
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
	}

843 844 845 846 847 848 849 850
	*peerp = peer;
	return (ISC_R_SUCCESS);

 cleanup:
	dns_peer_detach(&peer);
	return (result);
}

851
static isc_result_t
852
disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
853
	isc_result_t result;
854 855
	const cfg_obj_t *algorithms;
	const cfg_listelt_t *element;
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
	const char *str;
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_buffer_t b;

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
	isc_buffer_init(&b, str, strlen(str));
	isc_buffer_add(&b, strlen(str));
	CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL));

	algorithms = cfg_tuple_get(disabled, "algorithms");
	for (element = cfg_list_first(algorithms);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		isc_textregion_t r;
		dns_secalg_t alg;

876
		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
		r.length = strlen(r.base);

		result = dns_secalg_fromtext(&alg, &r);
		if (result != ISC_R_SUCCESS) {
			isc_uint8_t ui;
			result = isc_parse_uint8(&ui, r.base, 10);
			alg = ui;
		}
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(cfg_listelt_value(element),
				    ns_g_lctx, ISC_LOG_ERROR,
				    "invalid algorithm");
			CHECK(result);
		}
		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
	}
 cleanup:
	return (result);
}

897
static isc_boolean_t
898 899
on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
	const cfg_listelt_t *element;
900 901 902
	dns_fixedname_t fixed;
	dns_name_t *name;
	isc_result_t result;
903
	const cfg_obj_t *value;
904 905 906 907 908
	const char *str;
	isc_buffer_t b;

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
Automatic Updater's avatar
Automatic Updater committed
909

910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
	for (element = cfg_list_first(disablelist);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		value = cfg_listelt_value(element);
		str = cfg_obj_asstring(value);
		isc_buffer_init(&b, str, strlen(str));
		isc_buffer_add(&b, strlen(str));
		result = dns_name_fromtext(name, &b, dns_rootname,
					   ISC_TRUE, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		if (dns_name_equal(name, zonename))
			return (ISC_TRUE);
	}
	return (ISC_FALSE);
}

927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
static void
check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
	     isc_mem_t *mctx)
{
	char **argv = NULL;
	unsigned int i;
	isc_result_t result;

	result = dns_zone_getdbtype(*zonep, &argv, mctx);
	if (result != ISC_R_SUCCESS) {
		dns_zone_detach(zonep);
		return;
	}

	/*
	 * Check that all the arguments match.
	 */
	for (i = 0; i < dbtypec; i++)
		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
			dns_zone_detach(zonep);
			break;
		}

	/*
	 * Check that there are not extra arguments.
	 */
	if (i == dbtypec && argv[i] != NULL)
		dns_zone_detach(zonep);
	isc_mem_free(mctx, argv);
}

958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
static isc_result_t
setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
	isc_result_t result;
	dns_stats_t *zoneqrystats;

	zoneqrystats = NULL;
	if (on) {
		result = dns_generalstats_create(mctx, &zoneqrystats,
						 dns_nsstatscounter_max);
		if (result != ISC_R_SUCCESS)
			return (result);
	}
	dns_zone_setrequeststats(zone, zoneqrystats);
	if (zoneqrystats != NULL)
		dns_stats_detach(&zoneqrystats);

	return (ISC_R_SUCCESS);
}
976

977
/*
978 979
 * Configure 'view' according to 'vconfig', taking defaults from 'config'
 * where values are missing in 'vconfig'.
980
 *
981 982
 * When configuring the default view, 'vconfig' will be NULL and the
 * global defaults in 'config' used exclusively.
983
 */
984
static isc_result_t
985 986 987
configure_view(dns_view_t *view, const cfg_obj_t *config,
	       const cfg_obj_t *vconfig, isc_mem_t *mctx,
	       cfg_aclconfctx_t *actx, isc_boolean_t need_hints)
988
{
989 990 991 992 993 994 995 996
	const cfg_obj_t *maps[4];
	const cfg_obj_t *cfgmaps[3];
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *voptions = NULL;
	const cfg_obj_t *forwardtype;
	const cfg_obj_t *forwarders;
	const cfg_obj_t *alternates;
	const cfg_obj_t *zonelist;
997
#ifdef DLZ
998 999 1000
	const cfg_obj_t *dlz;
	unsigned int dlzargc;
	char **dlzargv;
1001
#endif
1002 1003 1004
	const cfg_obj_t *disabled;
	const cfg_obj_t *obj;
	const cfg_listelt_t *element;
1005
	in_port_t port;
1006
	dns_cache_t *cache = NULL;
1007
	isc_result_t result;
1008
	isc_uint32_t max_adb_size;
1009
	isc_uint32_t max_cache_size;
1010
	isc_uint32_t max_acache_size;
Mark Andrews's avatar
Mark Andrews committed
1011
	isc_uint32_t lame_ttl;
Brian Wellington's avatar
Brian Wellington committed
1012
	dns_tsig_keyring_t *ring;