PageRenderTime 125ms CodeModel.GetById 19ms app.highlight 82ms RepoModel.GetById 1ms app.codeStats 2ms

/contrib/bind9/bin/named/server.c

https://bitbucket.org/freebsd/freebsd-head/
C | 7648 lines | 5910 code | 887 blank | 851 comment | 1790 complexity | 0d51a127a90e8c0853cc6539ac9d6bce MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 1999-2003  Internet Software Consortium.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15 * PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18/* $Id: server.c,v 1.599.8.19 2012/02/22 00:33:32 each Exp $ */
  19
  20/*! \file */
  21
  22#include <config.h>
  23
  24#include <stdlib.h>
  25#include <unistd.h>
  26#include <limits.h>
  27#include <ctype.h>
  28#include <sys/types.h>
  29#include <sys/stat.h>
  30
  31#include <isc/app.h>
  32#include <isc/base64.h>
  33#include <isc/dir.h>
  34#include <isc/entropy.h>
  35#include <isc/file.h>
  36#include <isc/hash.h>
  37#include <isc/httpd.h>
  38#include <isc/lex.h>
  39#include <isc/parseint.h>
  40#include <isc/portset.h>
  41#include <isc/print.h>
  42#include <isc/resource.h>
  43#include <isc/sha2.h>
  44#include <isc/socket.h>
  45#include <isc/stat.h>
  46#include <isc/stats.h>
  47#include <isc/stdio.h>
  48#include <isc/string.h>
  49#include <isc/task.h>
  50#include <isc/timer.h>
  51#include <isc/util.h>
  52#include <isc/xml.h>
  53
  54#include <isccfg/namedconf.h>
  55
  56#include <bind9/check.h>
  57
  58#include <dns/acache.h>
  59#include <dns/adb.h>
  60#include <dns/cache.h>
  61#include <dns/db.h>
  62#include <dns/dispatch.h>
  63#include <dns/dlz.h>
  64#include <dns/dns64.h>
  65#include <dns/forward.h>
  66#include <dns/journal.h>
  67#include <dns/keytable.h>
  68#include <dns/keyvalues.h>
  69#include <dns/lib.h>
  70#include <dns/master.h>
  71#include <dns/masterdump.h>
  72#include <dns/order.h>
  73#include <dns/peer.h>
  74#include <dns/portlist.h>
  75#include <dns/rbt.h>
  76#include <dns/rdataclass.h>
  77#include <dns/rdataset.h>
  78#include <dns/rdatastruct.h>
  79#include <dns/resolver.h>
  80#include <dns/rootns.h>
  81#include <dns/secalg.h>
  82#include <dns/stats.h>
  83#include <dns/tkey.h>
  84#include <dns/tsig.h>
  85#include <dns/view.h>
  86#include <dns/zone.h>
  87#include <dns/zt.h>
  88
  89#include <dst/dst.h>
  90#include <dst/result.h>
  91
  92#include <named/client.h>
  93#include <named/config.h>
  94#include <named/control.h>
  95#include <named/interfacemgr.h>
  96#include <named/log.h>
  97#include <named/logconf.h>
  98#include <named/lwresd.h>
  99#include <named/main.h>
 100#include <named/os.h>
 101#include <named/server.h>
 102#include <named/statschannel.h>
 103#include <named/tkeyconf.h>
 104#include <named/tsigconf.h>
 105#include <named/zoneconf.h>
 106#ifdef HAVE_LIBSCF
 107#include <named/ns_smf_globals.h>
 108#include <stdlib.h>
 109#endif
 110
 111#ifndef PATH_MAX
 112#define PATH_MAX 1024
 113#endif
 114
 115/*%
 116 * Check an operation for failure.  Assumes that the function
 117 * using it has a 'result' variable and a 'cleanup' label.
 118 */
 119#define CHECK(op) \
 120	do { result = (op);					 \
 121	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
 122	} while (0)
 123
 124#define CHECKM(op, msg) \
 125	do { result = (op);					  \
 126	       if (result != ISC_R_SUCCESS) {			  \
 127			isc_log_write(ns_g_lctx,		  \
 128				      NS_LOGCATEGORY_GENERAL,	  \
 129				      NS_LOGMODULE_SERVER,	  \
 130				      ISC_LOG_ERROR,		  \
 131				      "%s: %s", msg,		  \
 132				      isc_result_totext(result)); \
 133			goto cleanup;				  \
 134		}						  \
 135	} while (0)						  \
 136
 137#define CHECKMF(op, msg, file) \
 138	do { result = (op);					  \
 139	       if (result != ISC_R_SUCCESS) {			  \
 140			isc_log_write(ns_g_lctx,		  \
 141				      NS_LOGCATEGORY_GENERAL,	  \
 142				      NS_LOGMODULE_SERVER,	  \
 143				      ISC_LOG_ERROR,		  \
 144				      "%s '%s': %s", msg, file,	  \
 145				      isc_result_totext(result)); \
 146			goto cleanup;				  \
 147		}						  \
 148	} while (0)						  \
 149
 150#define CHECKFATAL(op, msg) \
 151	do { result = (op);					  \
 152	       if (result != ISC_R_SUCCESS)			  \
 153			fatal(msg, result);			  \
 154	} while (0)						  \
 155
 156/*%
 157 * Maximum ADB size for views that share a cache.  Use this limit to suppress
 158 * the total of memory footprint, which should be the main reason for sharing
 159 * a cache.  Only effective when a finite max-cache-size is specified.
 160 * This is currently defined to be 8MB.
 161 */
 162#define MAX_ADB_SIZE_FOR_CACHESHARE	8388608
 163
 164struct ns_dispatch {
 165	isc_sockaddr_t			addr;
 166	unsigned int			dispatchgen;
 167	dns_dispatch_t			*dispatch;
 168	ISC_LINK(struct ns_dispatch)	link;
 169};
 170
 171struct ns_cache {
 172	dns_cache_t			*cache;
 173	dns_view_t			*primaryview;
 174	isc_boolean_t			needflush;
 175	isc_boolean_t			adbsizeadjusted;
 176	ISC_LINK(ns_cache_t)		link;
 177};
 178
 179struct dumpcontext {
 180	isc_mem_t			*mctx;
 181	isc_boolean_t			dumpcache;
 182	isc_boolean_t			dumpzones;
 183	FILE				*fp;
 184	ISC_LIST(struct viewlistentry)	viewlist;
 185	struct viewlistentry		*view;
 186	struct zonelistentry		*zone;
 187	dns_dumpctx_t			*mdctx;
 188	dns_db_t			*db;
 189	dns_db_t			*cache;
 190	isc_task_t			*task;
 191	dns_dbversion_t			*version;
 192};
 193
 194struct viewlistentry {
 195	dns_view_t			*view;
 196	ISC_LINK(struct viewlistentry)	link;
 197	ISC_LIST(struct zonelistentry)	zonelist;
 198};
 199
 200struct zonelistentry {
 201	dns_zone_t			*zone;
 202	ISC_LINK(struct zonelistentry)	link;
 203};
 204
 205/*%
 206 * Configuration context to retain for each view that allows
 207 * new zones to be added at runtime.
 208 */
 209struct cfg_context {
 210	isc_mem_t *			mctx;
 211	cfg_parser_t *			parser;
 212	cfg_obj_t *			config;
 213	cfg_parser_t *			nzparser;
 214	cfg_obj_t *			nzconfig;
 215	cfg_aclconfctx_t *		actx;
 216};
 217
 218/*
 219 * These zones should not leak onto the Internet.
 220 */
 221static const struct {
 222	const char	*zone;
 223	isc_boolean_t	rfc1918;
 224} empty_zones[] = {
 225	/* RFC 1918 */
 226	{ "10.IN-ADDR.ARPA", ISC_TRUE },
 227	{ "16.172.IN-ADDR.ARPA", ISC_TRUE },
 228	{ "17.172.IN-ADDR.ARPA", ISC_TRUE },
 229	{ "18.172.IN-ADDR.ARPA", ISC_TRUE },
 230	{ "19.172.IN-ADDR.ARPA", ISC_TRUE },
 231	{ "20.172.IN-ADDR.ARPA", ISC_TRUE },
 232	{ "21.172.IN-ADDR.ARPA", ISC_TRUE },
 233	{ "22.172.IN-ADDR.ARPA", ISC_TRUE },
 234	{ "23.172.IN-ADDR.ARPA", ISC_TRUE },
 235	{ "24.172.IN-ADDR.ARPA", ISC_TRUE },
 236	{ "25.172.IN-ADDR.ARPA", ISC_TRUE },
 237	{ "26.172.IN-ADDR.ARPA", ISC_TRUE },
 238	{ "27.172.IN-ADDR.ARPA", ISC_TRUE },
 239	{ "28.172.IN-ADDR.ARPA", ISC_TRUE },
 240	{ "29.172.IN-ADDR.ARPA", ISC_TRUE },
 241	{ "30.172.IN-ADDR.ARPA", ISC_TRUE },
 242	{ "31.172.IN-ADDR.ARPA", ISC_TRUE },
 243	{ "168.192.IN-ADDR.ARPA", ISC_TRUE },
 244
 245	/* RFC 5735 and RFC 5737 */
 246	{ "0.IN-ADDR.ARPA", ISC_FALSE },	/* THIS NETWORK */
 247	{ "127.IN-ADDR.ARPA", ISC_FALSE },	/* LOOPBACK */
 248	{ "254.169.IN-ADDR.ARPA", ISC_FALSE },	/* LINK LOCAL */
 249	{ "2.0.192.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET */
 250	{ "100.51.198.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET 2 */
 251	{ "113.0.203.IN-ADDR.ARPA", ISC_FALSE },	/* TEST NET 3 */
 252	{ "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE },	/* BROADCAST */
 253
 254	/* Local IPv6 Unicast Addresses */
 255	{ "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 },
 256	{ "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 },
 257	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
 258	{ "D.F.IP6.ARPA", ISC_FALSE },
 259	{ "8.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
 260	{ "9.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
 261	{ "A.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
 262	{ "B.E.F.IP6.ARPA", ISC_FALSE },	/* LINK LOCAL */
 263
 264	/* Example Prefix, RFC 3849. */
 265	{ "8.B.D.0.1.0.0.2.IP6.ARPA", ISC_FALSE },
 266
 267	{ NULL, ISC_FALSE }
 268};
 269
 270ISC_PLATFORM_NORETURN_PRE static void
 271fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
 272
 273static void
 274ns_server_reload(isc_task_t *task, isc_event_t *event);
 275
 276static isc_result_t
 277ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
 278			cfg_aclconfctx_t *actx,
 279			isc_mem_t *mctx, ns_listenelt_t **target);
 280static isc_result_t
 281ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
 282			 cfg_aclconfctx_t *actx,
 283			 isc_mem_t *mctx, ns_listenlist_t **target);
 284
 285static isc_result_t
 286configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
 287		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
 288
 289static isc_result_t
 290configure_alternates(const cfg_obj_t *config, dns_view_t *view,
 291		     const cfg_obj_t *alternates);
 292
 293static isc_result_t
 294configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
 295	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
 296	       cfg_aclconfctx_t *aclconf, isc_boolean_t added);
 297
 298static isc_result_t
 299add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
 300
 301static void
 302end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
 303
 304static void
 305newzone_cfgctx_destroy(void **cfgp);
 306
 307/*%
 308 * Configure a single view ACL at '*aclp'.  Get its configuration from
 309 * 'vconfig' (for per-view configuration) and maybe from 'config'
 310 */
 311static isc_result_t
 312configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
 313		   const char *aclname, const char *acltuplename,
 314		   cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
 315{
 316	isc_result_t result;
 317	const cfg_obj_t *maps[3];
 318	const cfg_obj_t *aclobj = NULL;
 319	int i = 0;
 320
 321	if (*aclp != NULL)
 322		dns_acl_detach(aclp);
 323	if (vconfig != NULL)
 324		maps[i++] = cfg_tuple_get(vconfig, "options");
 325	if (config != NULL) {
 326		const cfg_obj_t *options = NULL;
 327		(void)cfg_map_get(config, "options", &options);
 328		if (options != NULL)
 329			maps[i++] = options;
 330	}
 331	maps[i] = NULL;
 332
 333	(void)ns_config_get(maps, aclname, &aclobj);
 334	if (aclobj == NULL)
 335		/*
 336		 * No value available.	*aclp == NULL.
 337		 */
 338		return (ISC_R_SUCCESS);
 339
 340	if (acltuplename != NULL) {
 341		/*
 342		 * If the ACL is given in an optional tuple, retrieve it.
 343		 * The parser should have ensured that a valid object be
 344		 * returned.
 345		 */
 346		aclobj = cfg_tuple_get(aclobj, acltuplename);
 347	}
 348
 349	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
 350				    actx, mctx, 0, aclp);
 351
 352	return (result);
 353}
 354
 355/*%
 356 * Configure a sortlist at '*aclp'.  Essentially the same as
 357 * configure_view_acl() except it calls cfg_acl_fromconfig with a
 358 * nest_level value of 2.
 359 */
 360static isc_result_t
 361configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
 362			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
 363			dns_acl_t **aclp)
 364{
 365	isc_result_t result;
 366	const cfg_obj_t *maps[3];
 367	const cfg_obj_t *aclobj = NULL;
 368	int i = 0;
 369
 370	if (*aclp != NULL)
 371		dns_acl_detach(aclp);
 372	if (vconfig != NULL)
 373		maps[i++] = cfg_tuple_get(vconfig, "options");
 374	if (config != NULL) {
 375		const cfg_obj_t *options = NULL;
 376		(void)cfg_map_get(config, "options", &options);
 377		if (options != NULL)
 378			maps[i++] = options;
 379	}
 380	maps[i] = NULL;
 381
 382	(void)ns_config_get(maps, "sortlist", &aclobj);
 383	if (aclobj == NULL)
 384		return (ISC_R_SUCCESS);
 385
 386	/*
 387	 * Use a nest level of 3 for the "top level" of the sortlist;
 388	 * this means each entry in the top three levels will be stored
 389	 * as lists of separate, nested ACLs, rather than merged together
 390	 * into IP tables as is usually done with ACLs.
 391	 */
 392	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
 393				    actx, mctx, 3, aclp);
 394
 395	return (result);
 396}
 397
 398static isc_result_t
 399configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
 400			 const char *confname, const char *conftuplename,
 401			 isc_mem_t *mctx, dns_rbt_t **rbtp)
 402{
 403	isc_result_t result;
 404	const cfg_obj_t *maps[3];
 405	const cfg_obj_t *obj = NULL;
 406	const cfg_listelt_t *element;
 407	int i = 0;
 408	dns_fixedname_t fixed;
 409	dns_name_t *name;
 410	isc_buffer_t b;
 411	const char *str;
 412	const cfg_obj_t *nameobj;
 413
 414	if (*rbtp != NULL)
 415		dns_rbt_destroy(rbtp);
 416	if (vconfig != NULL)
 417		maps[i++] = cfg_tuple_get(vconfig, "options");
 418	if (config != NULL) {
 419		const cfg_obj_t *options = NULL;
 420		(void)cfg_map_get(config, "options", &options);
 421		if (options != NULL)
 422			maps[i++] = options;
 423	}
 424	maps[i] = NULL;
 425
 426	(void)ns_config_get(maps, confname, &obj);
 427	if (obj == NULL)
 428		/*
 429		 * No value available.	*rbtp == NULL.
 430		 */
 431		return (ISC_R_SUCCESS);
 432
 433	if (conftuplename != NULL) {
 434		obj = cfg_tuple_get(obj, conftuplename);
 435		if (cfg_obj_isvoid(obj))
 436			return (ISC_R_SUCCESS);
 437	}
 438
 439	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
 440	if (result != ISC_R_SUCCESS)
 441		return (result);
 442
 443	dns_fixedname_init(&fixed);
 444	name = dns_fixedname_name(&fixed);
 445	for (element = cfg_list_first(obj);
 446	     element != NULL;
 447	     element = cfg_list_next(element)) {
 448		nameobj = cfg_listelt_value(element);
 449		str = cfg_obj_asstring(nameobj);
 450		isc_buffer_init(&b, str, strlen(str));
 451		isc_buffer_add(&b, strlen(str));
 452		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
 453		/*
 454		 * We don't need the node data, but need to set dummy data to
 455		 * avoid a partial match with an empty node.  For example, if
 456		 * we have foo.example.com and bar.example.com, we'd get a match
 457		 * for baz.example.com, which is not the expected result.
 458		 * We simply use (void *)1 as the dummy data.
 459		 */
 460		result = dns_rbt_addname(*rbtp, name, (void *)1);
 461		if (result != ISC_R_SUCCESS) {
 462			cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
 463				    "failed to add %s for %s: %s",
 464				    str, confname, isc_result_totext(result));
 465			goto cleanup;
 466		}
 467
 468	}
 469
 470	return (result);
 471
 472  cleanup:
 473	dns_rbt_destroy(rbtp);
 474	return (result);
 475
 476}
 477
 478static isc_result_t
 479dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
 480		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
 481{
 482	dns_rdataclass_t viewclass;
 483	dns_rdata_dnskey_t keystruct;
 484	isc_uint32_t flags, proto, alg;
 485	const char *keystr, *keynamestr;
 486	unsigned char keydata[4096];
 487	isc_buffer_t keydatabuf;
 488	unsigned char rrdata[4096];
 489	isc_buffer_t rrdatabuf;
 490	isc_region_t r;
 491	dns_fixedname_t fkeyname;
 492	dns_name_t *keyname;
 493	isc_buffer_t namebuf;
 494	isc_result_t result;
 495	dst_key_t *dstkey = NULL;
 496
 497	INSIST(target != NULL && *target == NULL);
 498
 499	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
 500	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
 501	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
 502	keyname = dns_fixedname_name(&fkeyname);
 503	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
 504
 505	if (managed) {
 506		const char *initmethod;
 507		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
 508
 509		if (strcasecmp(initmethod, "initial-key") != 0) {
 510			cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
 511				    "managed key '%s': "
 512				    "invalid initialization method '%s'",
 513				    keynamestr, initmethod);
 514			result = ISC_R_FAILURE;
 515			goto cleanup;
 516		}
 517	}
 518
 519	if (vconfig == NULL)
 520		viewclass = dns_rdataclass_in;
 521	else {
 522		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
 523		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
 524					 &viewclass));
 525	}
 526	keystruct.common.rdclass = viewclass;
 527	keystruct.common.rdtype = dns_rdatatype_dnskey;
 528	/*
 529	 * The key data in keystruct is not dynamically allocated.
 530	 */
 531	keystruct.mctx = NULL;
 532
 533	ISC_LINK_INIT(&keystruct.common, link);
 534
 535	if (flags > 0xffff)
 536		CHECKM(ISC_R_RANGE, "key flags");
 537	if (proto > 0xff)
 538		CHECKM(ISC_R_RANGE, "key protocol");
 539	if (alg > 0xff)
 540		CHECKM(ISC_R_RANGE, "key algorithm");
 541	keystruct.flags = (isc_uint16_t)flags;
 542	keystruct.protocol = (isc_uint8_t)proto;
 543	keystruct.algorithm = (isc_uint8_t)alg;
 544
 545	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
 546	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
 547
 548	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
 549	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
 550	isc_buffer_usedregion(&keydatabuf, &r);
 551	keystruct.datalen = r.length;
 552	keystruct.data = r.base;
 553
 554	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
 555	     keystruct.algorithm == DST_ALG_RSAMD5) &&
 556	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
 557		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
 558			    "%s key '%s' has a weak exponent",
 559			    managed ? "managed" : "trusted",
 560			    keynamestr);
 561
 562	CHECK(dns_rdata_fromstruct(NULL,
 563				   keystruct.common.rdclass,
 564				   keystruct.common.rdtype,
 565				   &keystruct, &rrdatabuf));
 566	dns_fixedname_init(&fkeyname);
 567	isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
 568	isc_buffer_add(&namebuf, strlen(keynamestr));
 569	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
 570	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
 571			      mctx, &dstkey));
 572
 573	*target = dstkey;
 574	return (ISC_R_SUCCESS);
 575
 576 cleanup:
 577	if (result == DST_R_NOCRYPTO) {
 578		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
 579			    "ignoring %s key for '%s': no crypto support",
 580			    managed ? "managed" : "trusted",
 581			    keynamestr);
 582	} else if (result == DST_R_UNSUPPORTEDALG) {
 583		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
 584			    "skipping %s key for '%s': %s",
 585			    managed ? "managed" : "trusted",
 586			    keynamestr, isc_result_totext(result));
 587	} else {
 588		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
 589			    "configuring %s key for '%s': %s",
 590			    managed ? "managed" : "trusted",
 591			    keynamestr, isc_result_totext(result));
 592		result = ISC_R_FAILURE;
 593	}
 594
 595	if (dstkey != NULL)
 596		dst_key_free(&dstkey);
 597
 598	return (result);
 599}
 600
 601static isc_result_t
 602load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
 603	       dns_view_t *view, isc_boolean_t managed,
 604	       dns_name_t *keyname, isc_mem_t *mctx)
 605{
 606	const cfg_listelt_t *elt, *elt2;
 607	const cfg_obj_t *key, *keylist;
 608	dst_key_t *dstkey = NULL;
 609	isc_result_t result;
 610	dns_keytable_t *secroots = NULL;
 611
 612	CHECK(dns_view_getsecroots(view, &secroots));
 613
 614	for (elt = cfg_list_first(keys);
 615	     elt != NULL;
 616	     elt = cfg_list_next(elt)) {
 617		keylist = cfg_listelt_value(elt);
 618
 619		for (elt2 = cfg_list_first(keylist);
 620		     elt2 != NULL;
 621		     elt2 = cfg_list_next(elt2)) {
 622			key = cfg_listelt_value(elt2);
 623			result = dstkey_fromconfig(vconfig, key, managed,
 624						   &dstkey, mctx);
 625			if (result ==  DST_R_UNSUPPORTEDALG) {
 626				result = ISC_R_SUCCESS;
 627				continue;
 628			}
 629			if (result != ISC_R_SUCCESS)
 630				goto cleanup;
 631
 632			/*
 633			 * If keyname was specified, we only add that key.
 634			 */
 635			if (keyname != NULL &&
 636			    !dns_name_equal(keyname, dst_key_name(dstkey)))
 637			{
 638				dst_key_free(&dstkey);
 639				continue;
 640			}
 641
 642			CHECK(dns_keytable_add(secroots, managed, &dstkey));
 643		}
 644	}
 645
 646 cleanup:
 647	if (dstkey != NULL)
 648		dst_key_free(&dstkey);
 649	if (secroots != NULL)
 650		dns_keytable_detach(&secroots);
 651	if (result == DST_R_NOCRYPTO)
 652		result = ISC_R_SUCCESS;
 653	return (result);
 654}
 655
 656/*%
 657 * Configure DNSSEC keys for a view.
 658 *
 659 * The per-view configuration values and the server-global defaults are read
 660 * from 'vconfig' and 'config'.
 661 */
 662static isc_result_t
 663configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
 664			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
 665			  isc_boolean_t auto_dlv, isc_boolean_t auto_root,
 666			  isc_mem_t *mctx)
 667{
 668	isc_result_t result = ISC_R_SUCCESS;
 669	const cfg_obj_t *view_keys = NULL;
 670	const cfg_obj_t *global_keys = NULL;
 671	const cfg_obj_t *view_managed_keys = NULL;
 672	const cfg_obj_t *global_managed_keys = NULL;
 673	const cfg_obj_t *maps[4];
 674	const cfg_obj_t *voptions = NULL;
 675	const cfg_obj_t *options = NULL;
 676	const cfg_obj_t *obj = NULL;
 677	const char *directory;
 678	int i = 0;
 679
 680	/* We don't need trust anchors for the _bind view */
 681	if (strcmp(view->name, "_bind") == 0 &&
 682	    view->rdclass == dns_rdataclass_chaos) {
 683		return (ISC_R_SUCCESS);
 684	}
 685
 686	if (vconfig != NULL) {
 687		voptions = cfg_tuple_get(vconfig, "options");
 688		if (voptions != NULL) {
 689			(void) cfg_map_get(voptions, "trusted-keys",
 690					   &view_keys);
 691			(void) cfg_map_get(voptions, "managed-keys",
 692					   &view_managed_keys);
 693			maps[i++] = voptions;
 694		}
 695	}
 696
 697	if (config != NULL) {
 698		(void)cfg_map_get(config, "trusted-keys", &global_keys);
 699		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
 700		(void)cfg_map_get(config, "options", &options);
 701		if (options != NULL) {
 702			maps[i++] = options;
 703		}
 704	}
 705
 706	maps[i++] = ns_g_defaults;
 707	maps[i] = NULL;
 708
 709	result = dns_view_initsecroots(view, mctx);
 710	if (result != ISC_R_SUCCESS) {
 711		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 712			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
 713			      "couldn't create keytable");
 714		return (ISC_R_UNEXPECTED);
 715	}
 716
 717	if (auto_dlv && view->rdclass == dns_rdataclass_in) {
 718		const cfg_obj_t *builtin_keys = NULL;
 719		const cfg_obj_t *builtin_managed_keys = NULL;
 720
 721		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
 722			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
 723			      "using built-in DLV key for view %s",
 724			      view->name);
 725
 726		/*
 727		 * If bind.keys exists, it overrides the managed-keys
 728		 * clause hard-coded in ns_g_config.
 729		 */
 730		if (bindkeys != NULL) {
 731			(void)cfg_map_get(bindkeys, "trusted-keys",
 732					  &builtin_keys);
 733			(void)cfg_map_get(bindkeys, "managed-keys",
 734					  &builtin_managed_keys);
 735		} else {
 736			(void)cfg_map_get(ns_g_config, "trusted-keys",
 737					  &builtin_keys);
 738			(void)cfg_map_get(ns_g_config, "managed-keys",
 739					  &builtin_managed_keys);
 740		}
 741
 742		if (builtin_keys != NULL)
 743			CHECK(load_view_keys(builtin_keys, vconfig, view,
 744					     ISC_FALSE, view->dlv, mctx));
 745		if (builtin_managed_keys != NULL)
 746			CHECK(load_view_keys(builtin_managed_keys, vconfig,
 747					     view, ISC_TRUE, view->dlv, mctx));
 748	}
 749
 750	if (auto_root && view->rdclass == dns_rdataclass_in) {
 751		const cfg_obj_t *builtin_keys = NULL;
 752		const cfg_obj_t *builtin_managed_keys = NULL;
 753
 754		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
 755			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
 756			      "using built-in root key for view %s",
 757			      view->name);
 758
 759		/*
 760		 * If bind.keys exists, it overrides the managed-keys
 761		 * clause hard-coded in ns_g_config.
 762		 */
 763		if (bindkeys != NULL) {
 764			(void)cfg_map_get(bindkeys, "trusted-keys",
 765					  &builtin_keys);
 766			(void)cfg_map_get(bindkeys, "managed-keys",
 767					  &builtin_managed_keys);
 768		} else {
 769			(void)cfg_map_get(ns_g_config, "trusted-keys",
 770					  &builtin_keys);
 771			(void)cfg_map_get(ns_g_config, "managed-keys",
 772					  &builtin_managed_keys);
 773		}
 774
 775		if (builtin_keys != NULL)
 776			CHECK(load_view_keys(builtin_keys, vconfig, view,
 777					     ISC_FALSE, dns_rootname, mctx));
 778		if (builtin_managed_keys != NULL)
 779			CHECK(load_view_keys(builtin_managed_keys, vconfig,
 780					     view, ISC_TRUE, dns_rootname,
 781					     mctx));
 782	}
 783
 784	CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
 785			     NULL, mctx));
 786	CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
 787			     NULL, mctx));
 788
 789	if (view->rdclass == dns_rdataclass_in) {
 790		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
 791				     NULL, mctx));
 792		CHECK(load_view_keys(global_managed_keys, vconfig, view,
 793				     ISC_TRUE, NULL, mctx));
 794	}
 795
 796	/*
 797	 * Add key zone for managed-keys.
 798	 */
 799	obj = NULL;
 800	(void)ns_config_get(maps, "managed-keys-directory", &obj);
 801	directory = obj != NULL ? cfg_obj_asstring(obj) : NULL;
 802	CHECK(add_keydata_zone(view, directory, ns_g_mctx));
 803
 804  cleanup:
 805	return (result);
 806}
 807
 808static isc_result_t
 809mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
 810	const cfg_listelt_t *element;
 811	const cfg_obj_t *obj;
 812	const char *str;
 813	dns_fixedname_t fixed;
 814	dns_name_t *name;
 815	isc_boolean_t value;
 816	isc_result_t result;
 817	isc_buffer_t b;
 818
 819	dns_fixedname_init(&fixed);
 820	name = dns_fixedname_name(&fixed);
 821	for (element = cfg_list_first(mbs);
 822	     element != NULL;
 823	     element = cfg_list_next(element))
 824	{
 825		obj = cfg_listelt_value(element);
 826		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
 827		isc_buffer_init(&b, str, strlen(str));
 828		isc_buffer_add(&b, strlen(str));
 829		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
 830		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
 831		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
 832	}
 833
 834	result = ISC_R_SUCCESS;
 835
 836 cleanup:
 837	return (result);
 838}
 839
 840/*%
 841 * Get a dispatch appropriate for the resolver of a given view.
 842 */
 843static isc_result_t
 844get_view_querysource_dispatch(const cfg_obj_t **maps,
 845			      int af, dns_dispatch_t **dispatchp,
 846			      isc_boolean_t is_firstview)
 847{
 848	isc_result_t result = ISC_R_FAILURE;
 849	dns_dispatch_t *disp;
 850	isc_sockaddr_t sa;
 851	unsigned int attrs, attrmask;
 852	const cfg_obj_t *obj = NULL;
 853	unsigned int maxdispatchbuffers;
 854
 855	switch (af) {
 856	case AF_INET:
 857		result = ns_config_get(maps, "query-source", &obj);
 858		INSIST(result == ISC_R_SUCCESS);
 859		break;
 860	case AF_INET6:
 861		result = ns_config_get(maps, "query-source-v6", &obj);
 862		INSIST(result == ISC_R_SUCCESS);
 863		break;
 864	default:
 865		INSIST(0);
 866	}
 867
 868	sa = *(cfg_obj_assockaddr(obj));
 869	INSIST(isc_sockaddr_pf(&sa) == af);
 870
 871	/*
 872	 * If we don't support this address family, we're done!
 873	 */
 874	switch (af) {
 875	case AF_INET:
 876		result = isc_net_probeipv4();
 877		break;
 878	case AF_INET6:
 879		result = isc_net_probeipv6();
 880		break;
 881	default:
 882		INSIST(0);
 883	}
 884	if (result != ISC_R_SUCCESS)
 885		return (ISC_R_SUCCESS);
 886
 887	/*
 888	 * Try to find a dispatcher that we can share.
 889	 */
 890	attrs = 0;
 891	attrs |= DNS_DISPATCHATTR_UDP;
 892	switch (af) {
 893	case AF_INET:
 894		attrs |= DNS_DISPATCHATTR_IPV4;
 895		break;
 896	case AF_INET6:
 897		attrs |= DNS_DISPATCHATTR_IPV6;
 898		break;
 899	}
 900	if (isc_sockaddr_getport(&sa) == 0) {
 901		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
 902		maxdispatchbuffers = 4096;
 903	} else {
 904		INSIST(obj != NULL);
 905		if (is_firstview) {
 906			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
 907				    "using specific query-source port "
 908				    "suppresses port randomization and can be "
 909				    "insecure.");
 910		}
 911		maxdispatchbuffers = 1000;
 912	}
 913
 914	attrmask = 0;
 915	attrmask |= DNS_DISPATCHATTR_UDP;
 916	attrmask |= DNS_DISPATCHATTR_TCP;
 917	attrmask |= DNS_DISPATCHATTR_IPV4;
 918	attrmask |= DNS_DISPATCHATTR_IPV6;
 919
 920	disp = NULL;
 921	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
 922				     ns_g_taskmgr, &sa, 4096,
 923				     maxdispatchbuffers, 32768, 16411, 16433,
 924				     attrs, attrmask, &disp);
 925	if (result != ISC_R_SUCCESS) {
 926		isc_sockaddr_t any;
 927		char buf[ISC_SOCKADDR_FORMATSIZE];
 928
 929		switch (af) {
 930		case AF_INET:
 931			isc_sockaddr_any(&any);
 932			break;
 933		case AF_INET6:
 934			isc_sockaddr_any6(&any);
 935			break;
 936		}
 937		if (isc_sockaddr_equal(&sa, &any))
 938			return (ISC_R_SUCCESS);
 939		isc_sockaddr_format(&sa, buf, sizeof(buf));
 940		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 941			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
 942			      "could not get query source dispatcher (%s)",
 943			      buf);
 944		return (result);
 945	}
 946
 947	*dispatchp = disp;
 948
 949	return (ISC_R_SUCCESS);
 950}
 951
 952static isc_result_t
 953configure_order(dns_order_t *order, const cfg_obj_t *ent) {
 954	dns_rdataclass_t rdclass;
 955	dns_rdatatype_t rdtype;
 956	const cfg_obj_t *obj;
 957	dns_fixedname_t fixed;
 958	unsigned int mode = 0;
 959	const char *str;
 960	isc_buffer_t b;
 961	isc_result_t result;
 962	isc_boolean_t addroot;
 963
 964	result = ns_config_getclass(cfg_tuple_get(ent, "class"),
 965				    dns_rdataclass_any, &rdclass);
 966	if (result != ISC_R_SUCCESS)
 967		return (result);
 968
 969	result = ns_config_gettype(cfg_tuple_get(ent, "type"),
 970				   dns_rdatatype_any, &rdtype);
 971	if (result != ISC_R_SUCCESS)
 972		return (result);
 973
 974	obj = cfg_tuple_get(ent, "name");
 975	if (cfg_obj_isstring(obj))
 976		str = cfg_obj_asstring(obj);
 977	else
 978		str = "*";
 979	addroot = ISC_TF(strcmp(str, "*") == 0);
 980	isc_buffer_init(&b, str, strlen(str));
 981	isc_buffer_add(&b, strlen(str));
 982	dns_fixedname_init(&fixed);
 983	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
 984				   dns_rootname, 0, NULL);
 985	if (result != ISC_R_SUCCESS)
 986		return (result);
 987
 988	obj = cfg_tuple_get(ent, "ordering");
 989	INSIST(cfg_obj_isstring(obj));
 990	str = cfg_obj_asstring(obj);
 991	if (!strcasecmp(str, "fixed"))
 992		mode = DNS_RDATASETATTR_FIXEDORDER;
 993	else if (!strcasecmp(str, "random"))
 994		mode = DNS_RDATASETATTR_RANDOMIZE;
 995	else if (!strcasecmp(str, "cyclic"))
 996		mode = 0;
 997	else
 998		INSIST(0);
 999
1000	/*
1001	 * "*" should match everything including the root (BIND 8 compat).
1002	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1003	 * explicit entry for "." when the name is "*".
1004	 */
1005	if (addroot) {
1006		result = dns_order_add(order, dns_rootname,
1007				       rdtype, rdclass, mode);
1008		if (result != ISC_R_SUCCESS)
1009			return (result);
1010	}
1011
1012	return (dns_order_add(order, dns_fixedname_name(&fixed),
1013			      rdtype, rdclass, mode));
1014}
1015
1016static isc_result_t
1017configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1018	isc_netaddr_t na;
1019	dns_peer_t *peer;
1020	const cfg_obj_t *obj;
1021	const char *str;
1022	isc_result_t result;
1023	unsigned int prefixlen;
1024
1025	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1026
1027	peer = NULL;
1028	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1029	if (result != ISC_R_SUCCESS)
1030		return (result);
1031
1032	obj = NULL;
1033	(void)cfg_map_get(cpeer, "bogus", &obj);
1034	if (obj != NULL)
1035		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1036
1037	obj = NULL;
1038	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1039	if (obj != NULL)
1040		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1041
1042	obj = NULL;
1043	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1044	if (obj != NULL)
1045		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1046
1047	obj = NULL;
1048	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1049	if (obj != NULL)
1050		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1051
1052	obj = NULL;
1053	(void)cfg_map_get(cpeer, "edns", &obj);
1054	if (obj != NULL)
1055		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1056
1057	obj = NULL;
1058	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1059	if (obj != NULL) {
1060		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1061		if (udpsize < 512)
1062			udpsize = 512;
1063		if (udpsize > 4096)
1064			udpsize = 4096;
1065		CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
1066	}
1067
1068	obj = NULL;
1069	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1070	if (obj != NULL) {
1071		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1072		if (udpsize < 512)
1073			udpsize = 512;
1074		if (udpsize > 4096)
1075			udpsize = 4096;
1076		CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
1077	}
1078
1079	obj = NULL;
1080	(void)cfg_map_get(cpeer, "transfers", &obj);
1081	if (obj != NULL)
1082		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1083
1084	obj = NULL;
1085	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1086	if (obj != NULL) {
1087		str = cfg_obj_asstring(obj);
1088		if (strcasecmp(str, "many-answers") == 0)
1089			CHECK(dns_peer_settransferformat(peer,
1090							 dns_many_answers));
1091		else if (strcasecmp(str, "one-answer") == 0)
1092			CHECK(dns_peer_settransferformat(peer,
1093							 dns_one_answer));
1094		else
1095			INSIST(0);
1096	}
1097
1098	obj = NULL;
1099	(void)cfg_map_get(cpeer, "keys", &obj);
1100	if (obj != NULL) {
1101		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1102		if (result != ISC_R_SUCCESS)
1103			goto cleanup;
1104	}
1105
1106	obj = NULL;
1107	if (na.family == AF_INET)
1108		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1109	else
1110		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1111	if (obj != NULL) {
1112		result = dns_peer_settransfersource(peer,
1113						    cfg_obj_assockaddr(obj));
1114		if (result != ISC_R_SUCCESS)
1115			goto cleanup;
1116		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1117	}
1118
1119	obj = NULL;
1120	if (na.family == AF_INET)
1121		(void)cfg_map_get(cpeer, "notify-source", &obj);
1122	else
1123		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1124	if (obj != NULL) {
1125		result = dns_peer_setnotifysource(peer,
1126						  cfg_obj_assockaddr(obj));
1127		if (result != ISC_R_SUCCESS)
1128			goto cleanup;
1129		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1130	}
1131
1132	obj = NULL;
1133	if (na.family == AF_INET)
1134		(void)cfg_map_get(cpeer, "query-source", &obj);
1135	else
1136		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1137	if (obj != NULL) {
1138		result = dns_peer_setquerysource(peer,
1139						 cfg_obj_assockaddr(obj));
1140		if (result != ISC_R_SUCCESS)
1141			goto cleanup;
1142		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1143	}
1144
1145	*peerp = peer;
1146	return (ISC_R_SUCCESS);
1147
1148 cleanup:
1149	dns_peer_detach(&peer);
1150	return (result);
1151}
1152
1153static isc_result_t
1154disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1155	isc_result_t result;
1156	const cfg_obj_t *algorithms;
1157	const cfg_listelt_t *element;
1158	const char *str;
1159	dns_fixedname_t fixed;
1160	dns_name_t *name;
1161	isc_buffer_t b;
1162
1163	dns_fixedname_init(&fixed);
1164	name = dns_fixedname_name(&fixed);
1165	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1166	isc_buffer_init(&b, str, strlen(str));
1167	isc_buffer_add(&b, strlen(str));
1168	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1169
1170	algorithms = cfg_tuple_get(disabled, "algorithms");
1171	for (element = cfg_list_first(algorithms);
1172	     element != NULL;
1173	     element = cfg_list_next(element))
1174	{
1175		isc_textregion_t r;
1176		dns_secalg_t alg;
1177
1178		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1179		r.length = strlen(r.base);
1180
1181		result = dns_secalg_fromtext(&alg, &r);
1182		if (result != ISC_R_SUCCESS) {
1183			isc_uint8_t ui;
1184			result = isc_parse_uint8(&ui, r.base, 10);
1185			alg = ui;
1186		}
1187		if (result != ISC_R_SUCCESS) {
1188			cfg_obj_log(cfg_listelt_value(element),
1189				    ns_g_lctx, ISC_LOG_ERROR,
1190				    "invalid algorithm");
1191			CHECK(result);
1192		}
1193		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1194	}
1195 cleanup:
1196	return (result);
1197}
1198
1199static isc_boolean_t
1200on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1201	const cfg_listelt_t *element;
1202	dns_fixedname_t fixed;
1203	dns_name_t *name;
1204	isc_result_t result;
1205	const cfg_obj_t *value;
1206	const char *str;
1207	isc_buffer_t b;
1208
1209	dns_fixedname_init(&fixed);
1210	name = dns_fixedname_name(&fixed);
1211
1212	for (element = cfg_list_first(disablelist);
1213	     element != NULL;
1214	     element = cfg_list_next(element))
1215	{
1216		value = cfg_listelt_value(element);
1217		str = cfg_obj_asstring(value);
1218		isc_buffer_init(&b, str, strlen(str));
1219		isc_buffer_add(&b, strlen(str));
1220		result = dns_name_fromtext(name, &b, dns_rootname,
1221					   0, NULL);
1222		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1223		if (dns_name_equal(name, zonename))
1224			return (ISC_TRUE);
1225	}
1226	return (ISC_FALSE);
1227}
1228
1229static void
1230check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
1231	     isc_mem_t *mctx)
1232{
1233	char **argv = NULL;
1234	unsigned int i;
1235	isc_result_t result;
1236
1237	result = dns_zone_getdbtype(*zonep, &argv, mctx);
1238	if (result != ISC_R_SUCCESS) {
1239		dns_zone_detach(zonep);
1240		return;
1241	}
1242
1243	/*
1244	 * Check that all the arguments match.
1245	 */
1246	for (i = 0; i < dbtypec; i++)
1247		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1248			dns_zone_detach(zonep);
1249			break;
1250		}
1251
1252	/*
1253	 * Check that there are not extra arguments.
1254	 */
1255	if (i == dbtypec && argv[i] != NULL)
1256		dns_zone_detach(zonep);
1257	isc_mem_free(mctx, argv);
1258}
1259
1260static isc_result_t
1261setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
1262	isc_result_t result;
1263	isc_stats_t *zoneqrystats;
1264
1265	zoneqrystats = NULL;
1266	if (on) {
1267		result = isc_stats_create(mctx, &zoneqrystats,
1268					  dns_nsstatscounter_max);
1269		if (result != ISC_R_SUCCESS)
1270			return (result);
1271	}
1272	dns_zone_setrequeststats(zone, zoneqrystats);
1273	if (zoneqrystats != NULL)
1274		isc_stats_detach(&zoneqrystats);
1275
1276	return (ISC_R_SUCCESS);
1277}
1278
1279static ns_cache_t *
1280cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
1281	ns_cache_t *nsc;
1282
1283	for (nsc = ISC_LIST_HEAD(*cachelist);
1284	     nsc != NULL;
1285	     nsc = ISC_LIST_NEXT(nsc, link)) {
1286		if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1287			return (nsc);
1288	}
1289
1290	return (NULL);
1291}
1292
1293static isc_boolean_t
1294cache_reusable(dns_view_t *originview, dns_view_t *view,
1295	       isc_boolean_t new_zero_no_soattl)
1296{
1297	if (originview->checknames != view->checknames ||
1298	    dns_resolver_getzeronosoattl(originview->resolver) !=
1299	    new_zero_no_soattl ||
1300	    originview->acceptexpired != view->acceptexpired ||
1301	    originview->enablevalidation != view->enablevalidation ||
1302	    originview->maxcachettl != view->maxcachettl ||
1303	    originview->maxncachettl != view->maxncachettl) {
1304		return (ISC_FALSE);
1305	}
1306
1307	return (ISC_TRUE);
1308}
1309
1310static isc_boolean_t
1311cache_sharable(dns_view_t *originview, dns_view_t *view,
1312	       isc_boolean_t new_zero_no_soattl,
1313	       unsigned int new_cleaning_interval,
1314	       isc_uint32_t new_max_cache_size)
1315{
1316	/*
1317	 * If the cache cannot even reused for the same view, it cannot be
1318	 * shared with other views.
1319	 */
1320	if (!cache_reusable(originview, view, new_zero_no_soattl))
1321		return (ISC_FALSE);
1322
1323	/*
1324	 * Check other cache related parameters that must be consistent among
1325	 * the sharing views.
1326	 */
1327	if (dns_cache_getcleaninginterval(originview->cache) !=
1328	    new_cleaning_interval ||
1329	    dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
1330		return (ISC_FALSE);
1331	}
1332
1333	return (ISC_TRUE);
1334}
1335
1336/*
1337 * Callback from DLZ configure when the driver sets up a writeable zone
1338 */
1339static isc_result_t
1340dlzconfigure_callback(dns_view_t *view, dns_zone_t *zone) {
1341	dns_name_t *origin = dns_zone_getorigin(zone);
1342	dns_rdataclass_t zclass = view->rdclass;
1343	isc_result_t result;
1344
1345	result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
1346	if (result != ISC_R_SUCCESS)
1347		return result;
1348	dns_zone_setstats(zone, ns_g_server->zonestats);
1349
1350	return ns_zone_configure_writeable_dlz(view->dlzdatabase,
1351					       zone, zclass, origin);
1352}
1353
1354static isc_result_t
1355dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1356	      unsigned int prefixlen, const char *server,
1357	      const char *contact)
1358{
1359	char *cp;
1360	char reverse[48+sizeof("ip6.arpa.")];
1361	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1362	const char *sep = ": view ";
1363	const char *viewname = view->name;
1364	const unsigned char *s6;
1365	dns_fixedname_t fixed;
1366	dns_name_t *name;
1367	dns_zone_t *zone = NULL;
1368	int dns64_dbtypec = 4;
1369	isc_buffer_t b;
1370	isc_result_t result;
1371
1372	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1373		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1374
1375	if (!strcmp(viewname, "_default")) {
1376		sep = "";
1377		viewname = "";
1378	}
1379
1380	/*
1381	 * Construct the reverse name of the zone.
1382	 */
1383	cp = reverse;
1384	s6 = na->type.in6.s6_addr;
1385	while (prefixlen > 0) {
1386		prefixlen -= 8;
1387		sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf,
1388			(s6[prefixlen/8] >> 4) & 0xf);
1389		cp += 4;
1390	}
1391	strcat(cp, "ip6.arpa.");
1392
1393	/*
1394	 * Create the actual zone.
1395	 */
1396	if (server != NULL)
1397		dns64_dbtype[2] = server;
1398	if (contact != NULL)
1399		dns64_dbtype[3] = contact;
1400	dns_fixedname_init(&fixed);
1401	name = dns_fixedname_name(&fixed);
1402	isc_buffer_init(&b, reverse, strlen(reverse));
1403	isc_buffer_add(&b, strlen(reverse));
1404	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1405	CHECK(dns_zone_create(&zone, mctx));
1406	CHECK(dns_zone_setorigin(zone, name));
1407	dns_zone_setview(zone, view);
1408	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1409	dns_zone_setclass(zone, view->rdclass);
1410	dns_zone_settype(zone, dns_zone_master);
1411	dns_zone_setstats(zone, ns_g_server->zonestats);
1412	CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
1413	if (view->queryacl != NULL)
1414		dns_zone_setqueryacl(zone, view->queryacl);
1415	if (view->queryonacl != NULL)
1416		dns_zone_setqueryonacl(zone, view->queryonacl);
1417	dns_zone_setdialup(zone, dns_dialuptype_no);
1418	dns_zone_setnotifytype(zone, dns_notifytype_no);
1419	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
1420	CHECK(setquerystats(zone, mctx, ISC_FALSE));	/* XXXMPA */
1421	CHECK(dns_view_addzone(view, zone));
1422	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1423		      ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep,
1424		      viewname, reverse);
1425
1426cleanup:
1427	if (zone != NULL)
1428		dns_zone_detach(&zone);
1429	return (result);
1430}
1431
1432static isc_result_t
1433configure_rpz(dns_view_t *view, const cfg_listelt_t *element) {
1434	const cfg_obj_t *rpz_obj, *policy_obj;
1435	const char *str;
1436	dns_fixedname_t fixed;
1437	dns_name_t *origin;
1438	dns_rpz_zone_t *old, *new;
1439	dns_zone_t *zone = NULL;
1440	isc_result_t result;
1441	unsigned int l1, l2;
1442
1443	new = isc_mem_get(view->mctx, sizeof(*new));
1444	if (new == NULL) {
1445		result = ISC_R_NOMEMORY;
1446		goto cleanup;
1447	}
1448
1449	memset(new, 0, sizeof(*new));
1450	dns_name_init(&new->nsdname, NULL);
1451	dns_name_init(&new->origin, NULL);
1452	dns_name_init(&new->cname, NULL);
1453	ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link);
1454
1455	rpz_obj = cfg_listelt_value(element);
1456	policy_obj = cfg_tuple_get(rpz_obj, "policy");
1457	if (cfg_obj_isvoid(policy_obj)) {
1458		new->policy = DNS_RPZ_POLICY_GIVEN;
1459	} else {
1460		str = cfg_obj_asstring(policy_obj);
1461		new->policy = dns_rpz_str2policy(str);
1462		INSIST(new->policy != DNS_RPZ_POLICY_ERROR);
1463	}
1464
1465	dns_fixedname_init(&fixed);
1466	origin = dns_fixedname_name(&fixed);
1467	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "name"));
1468	result = dns_name_fromstring(origin, str, DNS_NAME_DOWNCASE, NULL);
1469	if (result != ISC_R_SUCCESS) {
1470		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1471			    "invalid zone '%s'", str);
1472		goto cleanup;
1473	}
1474
1475	result = dns_name_fromstring2(&new->nsdname, DNS_RPZ_NSDNAME_ZONE,
1476				      origin, DNS_NAME_DOWNCASE, view->mctx);
1477	if (result != ISC_R_SUCCESS) {
1478		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1479			    "invalid zone '%s'", str);
1480		goto cleanup;
1481	}
1482
1483	/*
1484	 * The origin is part of 'nsdname' so we don't need to keep it
1485	 * seperately.
1486	 */
1487	l1 = dns_name_countlabels(&new->nsdname);
1488	l2 = dns_name_countlabels(origin);
1489	dns_name_getlabelsequence(&new->nsdname, l1 - l2, l2, &new->origin);
1490
1491	/*
1492	 * Are we configured to with the reponse policy zone?
1493	 */
1494	result = dns_view_findzone(view, &new->origin, &zone);
1495	if (result != ISC_R_SUCCESS) {
1496		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1497			    "unknown zone '%s'", str);
1498		goto cleanup;
1499	}
1500
1501	if (dns_zone_gettype(zone) != dns_zone_master &&
1502	    dns_zone_gettype(zone) != dns_zone_slave) {
1503		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1504			     "zone '%s' is neither master nor slave", str);
1505		dns_zone_detach(&zone);
1506		result = DNS_R_NOTMASTER;
1507		goto cleanup;
1508	}
1509	dns_zone_detach(&zone);
1510
1511	for (old = ISC_LIST_HEAD(view->rpz_zones);
1512	     old != new;
1513	     old = ISC_LIST_NEXT(old, link)) {
1514		++new->num;
1515		if (dns_name_equal(&old->origin, &new->origin)) {
1516			cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1517				    "duplicate '%s'", str);
1518			result = DNS_R_DUPLICATE;
1519			goto cleanup;
1520		}
1521	}
1522
1523	if (new->policy == DNS_RPZ_POLICY_CNAME) {
1524		str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "cname"));
1525		result = dns_name_fromstring(&new->cname, str, 0, view->mctx);
1526		if (result != ISC_R_SUCCESS) {
1527			cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1528				    "invalid cname '%s'", str);
1529			goto cleanup;
1530		}
1531	}
1532
1533	return (ISC_R_SUCCESS);
1534
1535 cleanup:
1536	dns_rpz_view_destroy(view);
1537	return (result);
1538}
1539
1540/*
1541 * Configure 'view' according to 'vconfig', taking defaults from 'config'
1542 * where values are missing in 'vconfig'.
1543 *
1544 * When configuring the default view, 'vconfig' will be NULL and the
1545 * global defaults in 'config' used exclusively.
1546 */
1547static isc_result_t
1548configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
1549	       ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
1550	       isc_mem_t *mctx, cfg_aclconfctx_t *actx,
1551	       isc_boolean_t need_hints)
1552{
1553	const cfg_obj_t *maps[4];
1554	const cfg_obj_t *cfgmaps[3];
1555	const cfg_obj_t *optionmaps[3];
1556	const cfg_obj_t *options = NULL;
1557	const cfg_obj_t *voptions = NULL;
1558	const cfg_obj_t *forwardtype;
1559	const cfg_obj_t *forwarders;
1560	const cfg_obj_t *alternates;
1561	const cfg_obj_t *zonelist;
1562	const cfg_obj_t *dlz;
1563	unsigned int dlzargc;
1564	char **dlzargv;
1565	const cfg_obj_t *disabled;
1566	const cfg_obj_t *obj;
1567	const cfg_listelt_t *element;
1568	in_port_t port;
1569	dns_cache_t *cache = NULL;
1570	isc_result_t result;
1571	isc_uint32_t max_adb_size;
1572	unsigned int cleaning_interval;
1573	isc_uint32_t max_cache_size;
1574	isc_uint32_t max_acache_size;
1575	isc_uint32_t lame_ttl;
1576	dns_tsig_keyring_t *ring = NULL;
1577	dns_view_t *pview = NULL;	/* Production view */
1578	isc_mem_t *cmctx = NULL, *hmctx = NULL;
1579	dns_dispatch_t *dispatch4 = NULL;
1580	dns_dispatch_t *dispatch6 = NULL;
1581	isc_boolean_t reused_cache = ISC_FALSE;
1582	isc_boolean_t shared_cache = ISC_FALSE;
1583	int i = 0, j = 0, k = 0;
1584	const char *str;
1585	const char *cachename = NULL;
1586	dns_order_t *order = NULL;
1587	isc_uint32_t udpsize;
1588	unsigned int resopts = 0;
1589	dns_zone_t *zone = NULL;
1590	isc_uint32_t max_clients_per_query;
1591	const char *sep = ": view ";
1592	const char *viewname = view->name;
1593	const char *forview = " for view ";
1594	isc_boolean_t rfc1918;
1595	isc_boolean_t empty_zones_enable;
1596	const cfg_obj_t *disablelist = NULL;
1597	isc_stats_t *resstats = NULL;
1598	dns_stats_t *resquerystats = NULL;
1599	isc_boolean_t auto_dlv = ISC_FALSE;
1600	isc_boolean_t auto_root = ISC_FALSE;
1601	ns_cache_t *nsc;
1602	isc_boolean_t zero_no_soattl;
1603	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
1604	unsigned int query_timeout;
1605	struct cfg_context *nzctx;
1606
1607	REQUIRE(DNS_VIEW_VALID(view));
1608
1609	if (config != NULL)
1610		(void)cfg_map_get(config, "options", &options);
1611
1612	/*
1613	 * maps: view options, options, defaults
1614	 * cfgmaps: view options, config
1615	 * optionmaps: view options, options
1616	 */
1617	if (vconfig != NULL) {
1618		voptions = cfg_tuple_get(vconfig, "options");
1619		maps[i++] = voptions;
1620		optionmaps[j++] = voptions;
1621		cfgmaps[k++] = voptions;
1622	}
1623	if (options != NULL) {
1624		maps[i++] = options;
1625		optionmaps[j++] = options;
1626	}
1627
1628	maps[i++] = ns_g_defaults;
1629	maps[i] = NULL;
1630	optionmaps[j] = NULL;
1631	if (config != NULL)
1632		cfgmaps[k++] = config;
1633	cfgmaps[k] = NULL;
1634
1635	if (!strcmp(viewname, "_default")) {
1636		sep = "";
1637		viewname = "";
1638		forview = "";
1639		POST(forview);
1640	}
1641
1642	/*
1643	 * Set the view's port number for outgoing queries.
1644	 */
1645	CHECKM(ns_config_getport(config, &port), "port");
1646	dns_view_setdstport(view, port);
1647
1648	/*
1649	 * Create additional cache for this view and zones under the view
1650	 * if explicitly enabled.
1651	 * XXX950 default to on.
1652	 */
1653	obj = NULL;
1654	(void)ns_config_get(maps, "acache-enable", &obj);
1655	if (obj != NULL && cfg_obj_asboolean(obj)) {
1656		cmctx = NULL;
1657		CHECK(isc_mem_create(0, 0, &cmctx));
1658		CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
1659					ns_g_timermgr));
1660		isc_mem_setname(cmctx, "acache", NULL);
1661		isc_mem_detach(&cmctx);
1662	}
1663	if (view->acache != NULL) {
1664		obj = NULL;
1665		result = ns_config_get(maps, "acache-cleaning-interval", &obj);
1666		INSIST(result == ISC_R_SUCCESS);
1667		dns_acache_setcleaninginterval(view->acache,
1668					       cfg_obj_asuint32(obj) * 60);
1669
1670		obj = NULL;
1671		result = ns_config_get(maps, "max-acache-size", &obj);
1672		INSIST(result == ISC_R_SUCCESS);
1673		if (cfg_obj_isstring(obj)) {
1674			str = cfg_obj_asstring(obj);
1675			INSIST(strcasecmp(str, "unlimited") == 0);
1676			max_acache_size = ISC_UINT32_MAX;
1677		} else {
1678			isc_resourcevalue_t value;
1679
1680			value = cfg_obj_asuint64(obj);
1681			if (value > ISC_UINT32_MAX) {
1682				cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1683					    "'max-acache-size "
1684					    "%" ISC_PRINT_QUADFORMAT
1685					    "d' is too large",
1686					    value);
1687				result = ISC_R_RANGE;
1688				goto cleanup;
1689			}
1690			max_acache_size = (isc_uint32_t)value;
1691		}
1692		dns_acache_setcachesize(view->acache, max_acache_size);
1693	}
1694
1695	CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
1696				 ns_g_mctx, &view->queryacl));
1697	if (view->queryacl == NULL) {
1698		CHECK(configure_view_acl(NULL, ns_g_config, "allow-query",
1699					 NULL, actx, ns_g_mctx,
1700					 &view->queryacl));
1701	}
1702
1703	/*
1704	 * Configure the zones.
1705	 */
1706	zonelist = NULL;
1707	if (voptions != NULL)
1708		(void)cfg_map_get(voptions, "zone", &zonelist);
1709	else
1710		(void)cfg_map_get(config, "zone", &zonelist);
1711
1712	/*
1713	 * Load zone configuration
1714	 */
1715	for (element = cfg_list_first(zonelist);
1716	     element != NULL;
1717	     element = cfg_list_next(element))
1718	{
1719		const cfg_obj_t *zconfig = cfg_listelt_value(element);
1720		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
1721				     actx, ISC_FALSE));
1722	}
1723
1724	/*
1725	 * If we're allowing added zones, then load zone configuration
1726	 * from the newzone file for zones that were added during previous
1727	 * runs.
1728	 */
1729	nzctx = view->new_zone_config;
1730	if (nzctx != NULL && nzctx->nzconfig != NULL) {
1731		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1732			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
1733			      "loading additional zones for view '%s'",
1734			      view->name);
1735
1736		zonelist = NULL;
1737		cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
1738
1739		for (element = cfg_list_first(zonelist);
1740		     element != NULL;
1741		     element = cfg_list_next(element))
1742		{
1743			const cfg_obj_t *zconfig = cfg_listelt_value(element);
1744			CHECK(configure_zone(config, zconfig, vconfig,
1745					     mctx, view, actx,
1746					     ISC_TRUE));
1747		}
1748	}
1749
1750	/*
1751	 * Create Dynamically Loadable Zone driver.
1752	 */
1753	dlz = NULL;
1754	if (voptions != NULL)
1755		(void)cfg_map_get(voptions, "dlz", &dlz);
1756	else
1757		(void)cfg_map_get(config, "dlz", &dlz);
1758
1759	obj = NULL;
1760	if (dlz != NULL) {
1761		(void)cfg_map_get(cfg_tuple_get(dlz, "options"),
1762				  "database", &obj);
1763		if (obj != NULL) {
1764			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
1765			if (s == NULL) {
1766				result = ISC_R_NOMEMORY;
1767				goto cleanup;
1768			}
1769
1770			result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
1771			if (result != ISC_R_SUCCESS) {
1772				isc_mem_free(mctx, s);
1773				goto cleanup;
1774			}
1775
1776			obj = cfg_tuple_get(dlz, "name");
1777			result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),
1778					       dlzargv[0], dlzargc, dlzargv,
1779					       &view->dlzdatabase);
1780			isc_mem_free(mctx, s);
1781			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
1782			if (result != ISC_R_SUCCESS)
1783				goto cleanup;
1784
1785			/*
1786			 * If the dlz backend supports configuration,
1787			 * then call its configure method now.
1788			 */
1789			result = dns_dlzconfigure(view, dlzconfigure_callback);
1790			if (result != ISC_R_SUCCESS)
1791				goto cleanup;
1792		}
1793	}
1794
1795	/*
1796	 * Obtain configuration parameters that affect the decision of whether
1797	 * we can reuse/share an existing cache.
1798	 */
1799	obj = NULL;
1800	result = ns_config_get(maps, "cleaning-interval", &obj);
1801	INSIST(result == ISC_R_SUCCESS);
1802	cleaning_interval = cfg_obj_asuint32(obj) * 60;
1803
1804	obj = NULL;
1805	result = ns_config_get(maps, "max-cache-size", &obj);
1806	INSIST(result == ISC_R_SUCCESS);
1807	if (cfg_obj_isstring(obj)) {
1808		str = cfg_obj_asstring(obj);
1809		INSIST(strcasecmp(str, "unlimited") == 0);
1810		max_cache_size = ISC_UINT32_MAX;
1811	} else {
1812		isc_resourcevalue_t value;
1813		value = cfg_obj_asuint64(obj);
1814		if (value > ISC_UINT32_MAX) {
1815			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1816				    "'max-cache-size "
1817				    "%" ISC_PRINT_QUADFORMAT "d' is too large",
1818				    value);
1819			result = ISC_R_RANGE;
1820			goto cleanup;
1821		}
1822		max_cache_size = (isc_uint32_t)value;
1823	}
1824
1825	/* Check-names. */
1826	obj = NULL;
1827	result = ns_checknames_get(maps, "response", &obj);
1828	INSIST(result == ISC_R_SUCCESS);
1829
1830	str = cfg_obj_asstring(obj);
1831	if (strcasecmp(str, "fail") == 0) {
1832		resopts |= DNS_RESOLVER_CHECKNAMES |
1833			DNS_RESOLVER_CHECKNAMESFAIL;
1834		view->checknames = ISC_TRUE;
1835	} else if (strcasecmp(str, "warn") == 0) {
1836		resopts |= DNS_RESOLVER_CHECKNAMES;
1837		view->checknames = ISC_FALSE;
1838	} else if (strcasecmp(str, "ignore") == 0) {
1839		view->chec

Large files files are truncated, but you can click here to view the full file