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

18
/* $Id: server.c,v 1.522 2008/12/25 02:02:39 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
/*%
Tatuya JINMEI 神明達哉's avatar
Tatuya JINMEI 神明達哉 committed
259 260
 * Configure a single view ACL at '*aclp'.  Get its configuration from
 * 'vconfig' (for per-view configuration) and maybe from 'config'
261 262
 */
static isc_result_t
263
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
264
		   const char *aclname, cfg_aclconfctx_t *actx,
265
		   isc_mem_t *mctx, dns_acl_t **aclp)
266 267
{
	isc_result_t result;
268 269
	const cfg_obj_t *maps[3];
	const cfg_obj_t *aclobj = NULL;
270 271
	int i = 0;

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

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

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

	return (result);
}

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

360 361 362 363 364 365 366
	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)
367
		viewclass = dns_rdataclass_in;
368
	else {
369
		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
370 371
		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
					 &viewclass));
372
	}
373
	keystruct.common.rdclass = viewclass;
374
	keystruct.common.rdtype = dns_rdatatype_dnskey;
375
	/*
376
	 * The key data in keystruct is not dynamically allocated.
377 378 379 380 381
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

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

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

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

401 402 403 404 405 406 407
	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);

408 409 410 411 412
	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));
	dns_fixedname_init(&fkeyname);
413 414
	isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
	isc_buffer_add(&namebuf, strlen(keynamestr));
415 416 417 418 419 420 421 422 423 424 425
	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:
426 427 428 429 430 431 432 433 434 435 436
	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;
	}
437 438 439 440 441 442 443

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

	return (result);
}

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

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

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

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
	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,
485
						       keytable, mctx));
486
		}
487
	}
488

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

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

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

510 511 512 513 514 515 516 517 518 519 520
	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,
521
					ISC_FALSE, NULL));
522 523 524 525 526
		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
527

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

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

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

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

565
	sa = *(cfg_obj_assockaddr(obj));
566 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
	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;
	}
597 598 599 600 601 602 603 604 605 606 607 608 609
	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;
	}
610

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

	*dispatchp = disp;

	return (ISC_R_SUCCESS);
}

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

	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");
672
	if (cfg_obj_isstring(obj))
673 674 675
		str = cfg_obj_asstring(obj);
	else
		str = "*";
676
	addroot = ISC_TF(strcmp(str, "*") == 0);
677 678 679 680
	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,
681
				   dns_rootname, ISC_FALSE, NULL);
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
	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);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	obj = NULL;
804
	if (na.family == AF_INET)
805 806 807 808 809 810 811 812
		(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;
813
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
814
	}
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

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

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

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

850
static isc_result_t
851
disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
852
	isc_result_t result;
853 854
	const cfg_obj_t *algorithms;
	const cfg_listelt_t *element;
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
	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;

875
		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
		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);
}

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

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

909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
	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);
}

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

957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
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);
}
975

976
/*
977 978
 * Configure 'view' according to 'vconfig', taking defaults from 'config'
 * where values are missing in 'vconfig'.
979
 *
980 981
 * When configuring the default view, 'vconfig' will be NULL and the
 * global defaults in 'config' used exclusively.
982
 */
983
static isc_result_t
984 985 986
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)
987
{
988 989 990 991 992 993 994 995
	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;
996
#ifdef DLZ
997 998 999
	const cfg_obj_t *dlz;
	unsigned int dlzargc;
	char **dlzargv;
1000
#endif
1001 1002 1003
	const cfg_obj_t *disabled;
	const cfg_obj_t *obj;
	const cfg_listelt_t *element;
1004
	in_port_t port;
1005
	dns_cache_t *cache = NULL;
1006
	isc_result_t result;
1007
	isc_uint32_t max_adb_size;
1008
	isc_uint32_t max_cache_size;
1009
	isc_uint32_t max_acache_size;
Mark Andrews's avatar
Mark Andrews committed
1010
	isc_uint32_t lame_ttl;
Brian Wellington's avatar
Brian Wellington committed
1011
	dns_tsig_keyring_t *ring;
1012
	dns_view_t *pview = NULL;	/* Production view */