PageRenderTime 133ms CodeModel.GetById 2ms app.highlight 120ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/view.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1789 lines | 1430 code | 226 blank | 133 comment | 520 complexity | 7607acc3b8973e7dfaa49cd1e377790b MD5 | raw 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$ */
  19
  20/*! \file */
  21
  22#include <config.h>
  23
  24#include <isc/file.h>
  25#include <isc/hash.h>
  26#include <isc/print.h>
  27#include <isc/sha2.h>
  28#include <isc/stats.h>
  29#include <isc/string.h>		/* Required for HP/UX (and others?) */
  30#include <isc/task.h>
  31#include <isc/util.h>
  32
  33#include <dns/acache.h>
  34#include <dns/acl.h>
  35#include <dns/adb.h>
  36#include <dns/cache.h>
  37#include <dns/db.h>
  38#include <dns/dlz.h>
  39#ifdef BIND9
  40#include <dns/dns64.h>
  41#endif
  42#include <dns/dnssec.h>
  43#include <dns/events.h>
  44#include <dns/forward.h>
  45#include <dns/keytable.h>
  46#include <dns/keyvalues.h>
  47#include <dns/master.h>
  48#include <dns/masterdump.h>
  49#include <dns/order.h>
  50#include <dns/peer.h>
  51#include <dns/rbt.h>
  52#include <dns/rdataset.h>
  53#include <dns/request.h>
  54#include <dns/resolver.h>
  55#include <dns/result.h>
  56#include <dns/rpz.h>
  57#include <dns/stats.h>
  58#include <dns/tsig.h>
  59#include <dns/zone.h>
  60#include <dns/zt.h>
  61
  62#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
  63#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
  64#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
  65
  66#define DNS_VIEW_DELONLYHASH 111
  67
  68static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
  69static void adb_shutdown(isc_task_t *task, isc_event_t *event);
  70static void req_shutdown(isc_task_t *task, isc_event_t *event);
  71
  72isc_result_t
  73dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
  74		const char *name, dns_view_t **viewp)
  75{
  76	dns_view_t *view;
  77	isc_result_t result;
  78
  79	/*
  80	 * Create a view.
  81	 */
  82
  83	REQUIRE(name != NULL);
  84	REQUIRE(viewp != NULL && *viewp == NULL);
  85
  86	view = isc_mem_get(mctx, sizeof(*view));
  87	if (view == NULL)
  88		return (ISC_R_NOMEMORY);
  89	view->name = isc_mem_strdup(mctx, name);
  90	if (view->name == NULL) {
  91		result = ISC_R_NOMEMORY;
  92		goto cleanup_view;
  93	}
  94	result = isc_mutex_init(&view->lock);
  95	if (result != ISC_R_SUCCESS)
  96		goto cleanup_name;
  97
  98#ifdef BIND9
  99	view->zonetable = NULL;
 100	result = dns_zt_create(mctx, rdclass, &view->zonetable);
 101	if (result != ISC_R_SUCCESS) {
 102		UNEXPECTED_ERROR(__FILE__, __LINE__,
 103				 "dns_zt_create() failed: %s",
 104				 isc_result_totext(result));
 105		result = ISC_R_UNEXPECTED;
 106		goto cleanup_mutex;
 107	}
 108#endif
 109	view->secroots_priv = NULL;
 110	view->fwdtable = NULL;
 111	result = dns_fwdtable_create(mctx, &view->fwdtable);
 112	if (result != ISC_R_SUCCESS) {
 113		UNEXPECTED_ERROR(__FILE__, __LINE__,
 114				 "dns_fwdtable_create() failed: %s",
 115				 isc_result_totext(result));
 116		result = ISC_R_UNEXPECTED;
 117		goto cleanup_zt;
 118	}
 119
 120	view->acache = NULL;
 121	view->cache = NULL;
 122	view->cachedb = NULL;
 123	view->dlzdatabase = NULL;
 124	view->hints = NULL;
 125	view->resolver = NULL;
 126	view->adb = NULL;
 127	view->requestmgr = NULL;
 128	view->mctx = mctx;
 129	view->rdclass = rdclass;
 130	view->frozen = ISC_FALSE;
 131	view->task = NULL;
 132	result = isc_refcount_init(&view->references, 1);
 133	if (result != ISC_R_SUCCESS)
 134		goto cleanup_fwdtable;
 135	view->weakrefs = 0;
 136	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
 137			    DNS_VIEWATTR_REQSHUTDOWN);
 138	view->statickeys = NULL;
 139	view->dynamickeys = NULL;
 140	view->matchclients = NULL;
 141	view->matchdestinations = NULL;
 142	view->matchrecursiveonly = ISC_FALSE;
 143	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
 144	if (result != ISC_R_SUCCESS)
 145		goto cleanup_references;
 146	view->peers = NULL;
 147	view->order = NULL;
 148	view->delonly = NULL;
 149	view->rootdelonly = ISC_FALSE;
 150	view->rootexclude = NULL;
 151	view->resstats = NULL;
 152	view->resquerystats = NULL;
 153	view->cacheshared = ISC_FALSE;
 154	ISC_LIST_INIT(view->dns64);
 155	view->dns64cnt = 0;
 156
 157	/*
 158	 * Initialize configuration data with default values.
 159	 */
 160	view->recursion = ISC_TRUE;
 161	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
 162	view->additionalfromcache = ISC_TRUE;
 163	view->additionalfromauth = ISC_TRUE;
 164	view->enablednssec = ISC_TRUE;
 165	view->enablevalidation = ISC_TRUE;
 166	view->acceptexpired = ISC_FALSE;
 167	view->minimalresponses = ISC_FALSE;
 168	view->transfer_format = dns_one_answer;
 169	view->cacheacl = NULL;
 170	view->cacheonacl = NULL;
 171	view->queryacl = NULL;
 172	view->queryonacl = NULL;
 173	view->recursionacl = NULL;
 174	view->recursiononacl = NULL;
 175	view->sortlist = NULL;
 176	view->transferacl = NULL;
 177	view->notifyacl = NULL;
 178	view->updateacl = NULL;
 179	view->upfwdacl = NULL;
 180	view->denyansweracl = NULL;
 181	view->answeracl_exclude = NULL;
 182	view->denyanswernames = NULL;
 183	view->answernames_exclude = NULL;
 184	view->requestixfr = ISC_TRUE;
 185	view->provideixfr = ISC_TRUE;
 186	view->maxcachettl = 7 * 24 * 3600;
 187	view->maxncachettl = 3 * 3600;
 188	view->dstport = 53;
 189	view->preferred_glue = 0;
 190	view->flush = ISC_FALSE;
 191	view->dlv = NULL;
 192	view->maxudp = 0;
 193	view->v4_aaaa = dns_v4_aaaa_ok;
 194	view->v4_aaaa_acl = NULL;
 195	ISC_LIST_INIT(view->rpz_zones);
 196	dns_fixedname_init(&view->dlv_fixed);
 197	view->managed_keys = NULL;
 198#ifdef BIND9
 199	view->new_zone_file = NULL;
 200	view->new_zone_config = NULL;
 201	view->cfg_destroy = NULL;
 202
 203	result = dns_order_create(view->mctx, &view->order);
 204	if (result != ISC_R_SUCCESS)
 205		goto cleanup_dynkeys;
 206#endif
 207
 208	result = dns_peerlist_new(view->mctx, &view->peers);
 209	if (result != ISC_R_SUCCESS)
 210		goto cleanup_order;
 211
 212	result = dns_aclenv_init(view->mctx, &view->aclenv);
 213	if (result != ISC_R_SUCCESS)
 214		goto cleanup_peerlist;
 215
 216	ISC_LINK_INIT(view, link);
 217	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
 218		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
 219		       view, NULL, NULL, NULL);
 220	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
 221		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
 222		       view, NULL, NULL, NULL);
 223	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
 224		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
 225		       view, NULL, NULL, NULL);
 226	view->magic = DNS_VIEW_MAGIC;
 227
 228	*viewp = view;
 229
 230	return (ISC_R_SUCCESS);
 231
 232 cleanup_peerlist:
 233	dns_peerlist_detach(&view->peers);
 234
 235 cleanup_order:
 236#ifdef BIND9
 237	dns_order_detach(&view->order);
 238
 239 cleanup_dynkeys:
 240#endif
 241	dns_tsigkeyring_detach(&view->dynamickeys);
 242
 243 cleanup_references:
 244	isc_refcount_destroy(&view->references);
 245
 246 cleanup_fwdtable:
 247	dns_fwdtable_destroy(&view->fwdtable);
 248
 249 cleanup_zt:
 250#ifdef BIND9
 251	dns_zt_detach(&view->zonetable);
 252
 253 cleanup_mutex:
 254#endif
 255	DESTROYLOCK(&view->lock);
 256
 257 cleanup_name:
 258	isc_mem_free(mctx, view->name);
 259
 260 cleanup_view:
 261	isc_mem_put(mctx, view, sizeof(*view));
 262
 263	return (result);
 264}
 265
 266static inline void
 267destroy(dns_view_t *view) {
 268#ifdef BIND9
 269	dns_dns64_t *dns64;
 270#endif
 271
 272	REQUIRE(!ISC_LINK_LINKED(view, link));
 273	REQUIRE(isc_refcount_current(&view->references) == 0);
 274	REQUIRE(view->weakrefs == 0);
 275	REQUIRE(RESSHUTDOWN(view));
 276	REQUIRE(ADBSHUTDOWN(view));
 277	REQUIRE(REQSHUTDOWN(view));
 278
 279#ifdef BIND9
 280	if (view->order != NULL)
 281		dns_order_detach(&view->order);
 282#endif
 283	if (view->peers != NULL)
 284		dns_peerlist_detach(&view->peers);
 285
 286	if (view->dynamickeys != NULL) {
 287		isc_result_t result;
 288		char template[20];
 289		char keyfile[20];
 290		FILE *fp = NULL;
 291		int n;
 292
 293		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
 294			     view->name);
 295		if (n > 0 && (size_t)n < sizeof(keyfile)) {
 296			result = isc_file_mktemplate(keyfile, template,
 297						     sizeof(template));
 298			if (result == ISC_R_SUCCESS)
 299				(void)isc_file_openuniqueprivate(template, &fp);
 300		}
 301		if (fp == NULL)
 302			dns_tsigkeyring_detach(&view->dynamickeys);
 303		else {
 304			result = dns_tsigkeyring_dumpanddetach(
 305							&view->dynamickeys, fp);
 306			if (result == ISC_R_SUCCESS) {
 307				if (fclose(fp) == 0)
 308					result = isc_file_rename(template,
 309								 keyfile);
 310				if (result != ISC_R_SUCCESS)
 311					(void)remove(template);
 312			} else {
 313				(void)fclose(fp);
 314				(void)remove(template);
 315			}
 316		}
 317	}
 318	if (view->statickeys != NULL)
 319		dns_tsigkeyring_detach(&view->statickeys);
 320	if (view->adb != NULL)
 321		dns_adb_detach(&view->adb);
 322	if (view->resolver != NULL)
 323		dns_resolver_detach(&view->resolver);
 324#ifdef BIND9
 325	if (view->acache != NULL) {
 326		if (view->cachedb != NULL)
 327			dns_acache_putdb(view->acache, view->cachedb);
 328		dns_acache_detach(&view->acache);
 329	}
 330	dns_rpz_view_destroy(view);
 331#else
 332	INSIST(view->acache == NULL);
 333	INSIST(ISC_LIST_EMPTY(view->rpz_zones));
 334#endif
 335	if (view->requestmgr != NULL)
 336		dns_requestmgr_detach(&view->requestmgr);
 337	if (view->task != NULL)
 338		isc_task_detach(&view->task);
 339	if (view->hints != NULL)
 340		dns_db_detach(&view->hints);
 341	if (view->dlzdatabase != NULL)
 342		dns_dlzdestroy(&view->dlzdatabase);
 343	if (view->cachedb != NULL)
 344		dns_db_detach(&view->cachedb);
 345	if (view->cache != NULL)
 346		dns_cache_detach(&view->cache);
 347	if (view->matchclients != NULL)
 348		dns_acl_detach(&view->matchclients);
 349	if (view->matchdestinations != NULL)
 350		dns_acl_detach(&view->matchdestinations);
 351	if (view->cacheacl != NULL)
 352		dns_acl_detach(&view->cacheacl);
 353	if (view->cacheonacl != NULL)
 354		dns_acl_detach(&view->cacheonacl);
 355	if (view->queryacl != NULL)
 356		dns_acl_detach(&view->queryacl);
 357	if (view->queryonacl != NULL)
 358		dns_acl_detach(&view->queryonacl);
 359	if (view->recursionacl != NULL)
 360		dns_acl_detach(&view->recursionacl);
 361	if (view->recursiononacl != NULL)
 362		dns_acl_detach(&view->recursiononacl);
 363	if (view->sortlist != NULL)
 364		dns_acl_detach(&view->sortlist);
 365	if (view->transferacl != NULL)
 366		dns_acl_detach(&view->transferacl);
 367	if (view->notifyacl != NULL)
 368		dns_acl_detach(&view->notifyacl);
 369	if (view->updateacl != NULL)
 370		dns_acl_detach(&view->updateacl);
 371	if (view->upfwdacl != NULL)
 372		dns_acl_detach(&view->upfwdacl);
 373	if (view->denyansweracl != NULL)
 374		dns_acl_detach(&view->denyansweracl);
 375	if (view->v4_aaaa_acl != NULL)
 376		dns_acl_detach(&view->v4_aaaa_acl);
 377	if (view->answeracl_exclude != NULL)
 378		dns_rbt_destroy(&view->answeracl_exclude);
 379	if (view->denyanswernames != NULL)
 380		dns_rbt_destroy(&view->denyanswernames);
 381	if (view->answernames_exclude != NULL)
 382		dns_rbt_destroy(&view->answernames_exclude);
 383	if (view->delonly != NULL) {
 384		dns_name_t *name;
 385		int i;
 386
 387		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
 388			name = ISC_LIST_HEAD(view->delonly[i]);
 389			while (name != NULL) {
 390				ISC_LIST_UNLINK(view->delonly[i], name, link);
 391				dns_name_free(name, view->mctx);
 392				isc_mem_put(view->mctx, name, sizeof(*name));
 393				name = ISC_LIST_HEAD(view->delonly[i]);
 394			}
 395		}
 396		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
 397			    DNS_VIEW_DELONLYHASH);
 398		view->delonly = NULL;
 399	}
 400	if (view->rootexclude != NULL) {
 401		dns_name_t *name;
 402		int i;
 403
 404		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
 405			name = ISC_LIST_HEAD(view->rootexclude[i]);
 406			while (name != NULL) {
 407				ISC_LIST_UNLINK(view->rootexclude[i],
 408						name, link);
 409				dns_name_free(name, view->mctx);
 410				isc_mem_put(view->mctx, name, sizeof(*name));
 411				name = ISC_LIST_HEAD(view->rootexclude[i]);
 412			}
 413		}
 414		isc_mem_put(view->mctx, view->rootexclude,
 415			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
 416		view->rootexclude = NULL;
 417	}
 418	if (view->resstats != NULL)
 419		isc_stats_detach(&view->resstats);
 420	if (view->resquerystats != NULL)
 421		dns_stats_detach(&view->resquerystats);
 422	if (view->secroots_priv != NULL)
 423		dns_keytable_detach(&view->secroots_priv);
 424#ifdef BIND9
 425	for (dns64 = ISC_LIST_HEAD(view->dns64);
 426	     dns64 != NULL;
 427	     dns64 = ISC_LIST_HEAD(view->dns64)) {
 428		dns_dns64_unlink(&view->dns64, dns64);
 429		dns_dns64_destroy(&dns64);
 430	}
 431	if (view->managed_keys != NULL)
 432		dns_zone_detach(&view->managed_keys);
 433	dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
 434#endif
 435	dns_fwdtable_destroy(&view->fwdtable);
 436	dns_aclenv_destroy(&view->aclenv);
 437	DESTROYLOCK(&view->lock);
 438	isc_refcount_destroy(&view->references);
 439	isc_mem_free(view->mctx, view->name);
 440	isc_mem_put(view->mctx, view, sizeof(*view));
 441}
 442
 443/*
 444 * Return true iff 'view' may be freed.
 445 * The caller must be holding the view lock.
 446 */
 447static isc_boolean_t
 448all_done(dns_view_t *view) {
 449
 450	if (isc_refcount_current(&view->references) == 0 &&
 451	    view->weakrefs == 0 &&
 452	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
 453		return (ISC_TRUE);
 454
 455	return (ISC_FALSE);
 456}
 457
 458void
 459dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
 460
 461	REQUIRE(DNS_VIEW_VALID(source));
 462	REQUIRE(targetp != NULL && *targetp == NULL);
 463
 464	isc_refcount_increment(&source->references, NULL);
 465
 466	*targetp = source;
 467}
 468
 469static void
 470view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
 471	dns_view_t *view;
 472	unsigned int refs;
 473	isc_boolean_t done = ISC_FALSE;
 474
 475	REQUIRE(viewp != NULL);
 476	view = *viewp;
 477	REQUIRE(DNS_VIEW_VALID(view));
 478
 479	if (flush)
 480		view->flush = ISC_TRUE;
 481	isc_refcount_decrement(&view->references, &refs);
 482	if (refs == 0) {
 483		LOCK(&view->lock);
 484		if (!RESSHUTDOWN(view))
 485			dns_resolver_shutdown(view->resolver);
 486		if (!ADBSHUTDOWN(view))
 487			dns_adb_shutdown(view->adb);
 488		if (!REQSHUTDOWN(view))
 489			dns_requestmgr_shutdown(view->requestmgr);
 490#ifdef BIND9
 491		if (view->acache != NULL)
 492			dns_acache_shutdown(view->acache);
 493		if (view->flush)
 494			dns_zt_flushanddetach(&view->zonetable);
 495		else
 496			dns_zt_detach(&view->zonetable);
 497		if (view->managed_keys != NULL) {
 498			if (view->flush)
 499				dns_zone_flush(view->managed_keys);
 500			dns_zone_detach(&view->managed_keys);
 501		}
 502#endif
 503		done = all_done(view);
 504		UNLOCK(&view->lock);
 505	}
 506
 507	*viewp = NULL;
 508
 509	if (done)
 510		destroy(view);
 511}
 512
 513void
 514dns_view_flushanddetach(dns_view_t **viewp) {
 515	view_flushanddetach(viewp, ISC_TRUE);
 516}
 517
 518void
 519dns_view_detach(dns_view_t **viewp) {
 520	view_flushanddetach(viewp, ISC_FALSE);
 521}
 522
 523#ifdef BIND9
 524static isc_result_t
 525dialup(dns_zone_t *zone, void *dummy) {
 526	UNUSED(dummy);
 527	dns_zone_dialup(zone);
 528	return (ISC_R_SUCCESS);
 529}
 530
 531void
 532dns_view_dialup(dns_view_t *view) {
 533	REQUIRE(DNS_VIEW_VALID(view));
 534	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
 535}
 536#endif
 537
 538void
 539dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
 540
 541	REQUIRE(DNS_VIEW_VALID(source));
 542	REQUIRE(targetp != NULL && *targetp == NULL);
 543
 544	LOCK(&source->lock);
 545	source->weakrefs++;
 546	UNLOCK(&source->lock);
 547
 548	*targetp = source;
 549}
 550
 551void
 552dns_view_weakdetach(dns_view_t **viewp) {
 553	dns_view_t *view;
 554	isc_boolean_t done = ISC_FALSE;
 555
 556	REQUIRE(viewp != NULL);
 557	view = *viewp;
 558	REQUIRE(DNS_VIEW_VALID(view));
 559
 560	LOCK(&view->lock);
 561
 562	INSIST(view->weakrefs > 0);
 563	view->weakrefs--;
 564	done = all_done(view);
 565
 566	UNLOCK(&view->lock);
 567
 568	*viewp = NULL;
 569
 570	if (done)
 571		destroy(view);
 572}
 573
 574static void
 575resolver_shutdown(isc_task_t *task, isc_event_t *event) {
 576	dns_view_t *view = event->ev_arg;
 577	isc_boolean_t done;
 578
 579	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
 580	REQUIRE(DNS_VIEW_VALID(view));
 581	REQUIRE(view->task == task);
 582
 583	UNUSED(task);
 584
 585	LOCK(&view->lock);
 586
 587	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
 588	done = all_done(view);
 589
 590	UNLOCK(&view->lock);
 591
 592	isc_event_free(&event);
 593
 594	if (done)
 595		destroy(view);
 596}
 597
 598static void
 599adb_shutdown(isc_task_t *task, isc_event_t *event) {
 600	dns_view_t *view = event->ev_arg;
 601	isc_boolean_t done;
 602
 603	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
 604	REQUIRE(DNS_VIEW_VALID(view));
 605	REQUIRE(view->task == task);
 606
 607	UNUSED(task);
 608
 609	LOCK(&view->lock);
 610
 611	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
 612	done = all_done(view);
 613
 614	UNLOCK(&view->lock);
 615
 616	isc_event_free(&event);
 617
 618	if (done)
 619		destroy(view);
 620}
 621
 622static void
 623req_shutdown(isc_task_t *task, isc_event_t *event) {
 624	dns_view_t *view = event->ev_arg;
 625	isc_boolean_t done;
 626
 627	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
 628	REQUIRE(DNS_VIEW_VALID(view));
 629	REQUIRE(view->task == task);
 630
 631	UNUSED(task);
 632
 633	LOCK(&view->lock);
 634
 635	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
 636	done = all_done(view);
 637
 638	UNLOCK(&view->lock);
 639
 640	isc_event_free(&event);
 641
 642	if (done)
 643		destroy(view);
 644}
 645
 646isc_result_t
 647dns_view_createresolver(dns_view_t *view,
 648			isc_taskmgr_t *taskmgr, unsigned int ntasks,
 649			isc_socketmgr_t *socketmgr,
 650			isc_timermgr_t *timermgr,
 651			unsigned int options,
 652			dns_dispatchmgr_t *dispatchmgr,
 653			dns_dispatch_t *dispatchv4,
 654			dns_dispatch_t *dispatchv6)
 655{
 656	isc_result_t result;
 657	isc_event_t *event;
 658	isc_mem_t *mctx = NULL;
 659
 660	REQUIRE(DNS_VIEW_VALID(view));
 661	REQUIRE(!view->frozen);
 662	REQUIRE(view->resolver == NULL);
 663
 664	result = isc_task_create(taskmgr, 0, &view->task);
 665	if (result != ISC_R_SUCCESS)
 666		return (result);
 667	isc_task_setname(view->task, "view", view);
 668
 669	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
 670				     timermgr, options, dispatchmgr,
 671				     dispatchv4, dispatchv6,
 672				     &view->resolver);
 673	if (result != ISC_R_SUCCESS) {
 674		isc_task_detach(&view->task);
 675		return (result);
 676	}
 677	event = &view->resevent;
 678	dns_resolver_whenshutdown(view->resolver, view->task, &event);
 679	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
 680
 681	result = isc_mem_create(0, 0, &mctx);
 682	if (result != ISC_R_SUCCESS) {
 683		dns_resolver_shutdown(view->resolver);
 684		return (result);
 685	}
 686
 687	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
 688	isc_mem_setname(mctx, "ADB", NULL);
 689	isc_mem_detach(&mctx);
 690	if (result != ISC_R_SUCCESS) {
 691		dns_resolver_shutdown(view->resolver);
 692		return (result);
 693	}
 694	event = &view->adbevent;
 695	dns_adb_whenshutdown(view->adb, view->task, &event);
 696	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
 697
 698	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
 699				      dns_resolver_taskmgr(view->resolver),
 700				      dns_resolver_dispatchmgr(view->resolver),
 701				      dns_resolver_dispatchv4(view->resolver),
 702				      dns_resolver_dispatchv6(view->resolver),
 703				      &view->requestmgr);
 704	if (result != ISC_R_SUCCESS) {
 705		dns_adb_shutdown(view->adb);
 706		dns_resolver_shutdown(view->resolver);
 707		return (result);
 708	}
 709	event = &view->reqevent;
 710	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
 711	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
 712
 713	return (ISC_R_SUCCESS);
 714}
 715
 716void
 717dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
 718	dns_view_setcache2(view, cache, ISC_FALSE);
 719}
 720
 721void
 722dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
 723	REQUIRE(DNS_VIEW_VALID(view));
 724	REQUIRE(!view->frozen);
 725
 726	view->cacheshared = shared;
 727	if (view->cache != NULL) {
 728#ifdef BIND9
 729		if (view->acache != NULL)
 730			dns_acache_putdb(view->acache, view->cachedb);
 731#endif
 732		dns_db_detach(&view->cachedb);
 733		dns_cache_detach(&view->cache);
 734	}
 735	dns_cache_attach(cache, &view->cache);
 736	dns_cache_attachdb(cache, &view->cachedb);
 737	INSIST(DNS_DB_VALID(view->cachedb));
 738
 739#ifdef BIND9
 740	if (view->acache != NULL)
 741		dns_acache_setdb(view->acache, view->cachedb);
 742#endif
 743}
 744
 745isc_boolean_t
 746dns_view_iscacheshared(dns_view_t *view) {
 747	REQUIRE(DNS_VIEW_VALID(view));
 748
 749	return (view->cacheshared);
 750}
 751
 752void
 753dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
 754	REQUIRE(DNS_VIEW_VALID(view));
 755	REQUIRE(!view->frozen);
 756	REQUIRE(view->hints == NULL);
 757	REQUIRE(dns_db_iszone(hints));
 758
 759	dns_db_attach(hints, &view->hints);
 760}
 761
 762void
 763dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
 764	REQUIRE(DNS_VIEW_VALID(view));
 765	REQUIRE(ring != NULL);
 766	if (view->statickeys != NULL)
 767		dns_tsigkeyring_detach(&view->statickeys);
 768	dns_tsigkeyring_attach(ring, &view->statickeys);
 769}
 770
 771void
 772dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
 773	REQUIRE(DNS_VIEW_VALID(view));
 774	REQUIRE(ring != NULL);
 775	if (view->dynamickeys != NULL)
 776		dns_tsigkeyring_detach(&view->dynamickeys);
 777	dns_tsigkeyring_attach(ring, &view->dynamickeys);
 778}
 779
 780void
 781dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) {
 782	REQUIRE(DNS_VIEW_VALID(view));
 783	REQUIRE(ringp != NULL && *ringp == NULL);
 784	if (view->dynamickeys != NULL)
 785		dns_tsigkeyring_attach(view->dynamickeys, ringp);
 786}
 787
 788void
 789dns_view_restorekeyring(dns_view_t *view) {
 790	FILE *fp;
 791	char keyfile[20];
 792	int n;
 793
 794	REQUIRE(DNS_VIEW_VALID(view));
 795
 796	if (view->dynamickeys != NULL) {
 797		n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys",
 798			     view->name);
 799		if (n > 0 && (size_t)n < sizeof(keyfile)) {
 800			fp = fopen(keyfile, "r");
 801			if (fp != NULL) {
 802				dns_keyring_restore(view->dynamickeys, fp);
 803				(void)fclose(fp);
 804			}
 805		}
 806	}
 807}
 808
 809void
 810dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
 811	REQUIRE(DNS_VIEW_VALID(view));
 812	view->dstport = dstport;
 813}
 814
 815void
 816dns_view_freeze(dns_view_t *view) {
 817	REQUIRE(DNS_VIEW_VALID(view));
 818	REQUIRE(!view->frozen);
 819
 820	if (view->resolver != NULL) {
 821		INSIST(view->cachedb != NULL);
 822		dns_resolver_freeze(view->resolver);
 823	}
 824	view->frozen = ISC_TRUE;
 825}
 826
 827#ifdef BIND9
 828void
 829dns_view_thaw(dns_view_t *view) {
 830	REQUIRE(DNS_VIEW_VALID(view));
 831	REQUIRE(view->frozen);
 832
 833	view->frozen = ISC_FALSE;
 834}
 835
 836isc_result_t
 837dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
 838	isc_result_t result;
 839
 840	REQUIRE(DNS_VIEW_VALID(view));
 841	REQUIRE(!view->frozen);
 842
 843	result = dns_zt_mount(view->zonetable, zone);
 844
 845	return (result);
 846}
 847#endif
 848
 849#ifdef BIND9
 850isc_result_t
 851dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
 852	isc_result_t result;
 853
 854	REQUIRE(DNS_VIEW_VALID(view));
 855
 856	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
 857	if (result == DNS_R_PARTIALMATCH) {
 858		dns_zone_detach(zonep);
 859		result = ISC_R_NOTFOUND;
 860	}
 861
 862	return (result);
 863}
 864#endif
 865
 866isc_result_t
 867dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
 868	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
 869	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
 870	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
 871	return (dns_view_find2(view, name, type, now, options, use_hints,
 872			       ISC_FALSE, dbp, nodep, foundname, rdataset,
 873			       sigrdataset));
 874}
 875
 876isc_result_t
 877dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
 878	       isc_stdtime_t now, unsigned int options,
 879	       isc_boolean_t use_hints, isc_boolean_t use_static_stub,
 880	       dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
 881	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 882{
 883	isc_result_t result;
 884	dns_db_t *db, *zdb;
 885	dns_dbnode_t *node, *znode;
 886	isc_boolean_t is_cache, is_staticstub_zone;
 887	dns_rdataset_t zrdataset, zsigrdataset;
 888	dns_zone_t *zone;
 889
 890#ifndef BIND9
 891	UNUSED(use_hints);
 892	UNUSED(use_static_stub);
 893#endif
 894
 895	/*
 896	 * Find an rdataset whose owner name is 'name', and whose type is
 897	 * 'type'.
 898	 */
 899
 900	REQUIRE(DNS_VIEW_VALID(view));
 901	REQUIRE(view->frozen);
 902	REQUIRE(type != dns_rdatatype_rrsig);
 903	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
 904	REQUIRE(nodep == NULL || *nodep == NULL);
 905
 906	/*
 907	 * Initialize.
 908	 */
 909	dns_rdataset_init(&zrdataset);
 910	dns_rdataset_init(&zsigrdataset);
 911	zdb = NULL;
 912	znode = NULL;
 913
 914	/*
 915	 * Find a database to answer the query.
 916	 */
 917	zone = NULL;
 918	db = NULL;
 919	node = NULL;
 920	is_staticstub_zone = ISC_FALSE;
 921#ifdef BIND9
 922	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
 923	if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
 924	    !use_static_stub) {
 925		result = ISC_R_NOTFOUND;
 926	}
 927	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
 928		result = dns_zone_getdb(zone, &db);
 929		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
 930			dns_db_attach(view->cachedb, &db);
 931		else if (result != ISC_R_SUCCESS)
 932			goto cleanup;
 933		if (dns_zone_gettype(zone) == dns_zone_staticstub &&
 934		    dns_name_equal(name, dns_zone_getorigin(zone))) {
 935			is_staticstub_zone = ISC_TRUE;
 936		}
 937	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
 938		dns_db_attach(view->cachedb, &db);
 939#else
 940	result = ISC_R_NOTFOUND;
 941	if (view->cachedb != NULL)
 942		dns_db_attach(view->cachedb, &db);
 943#endif /* BIND9 */
 944	else
 945		goto cleanup;
 946
 947	is_cache = dns_db_iscache(db);
 948
 949 db_find:
 950	/*
 951	 * Now look for an answer in the database.
 952	 */
 953	result = dns_db_find(db, name, NULL, type, options,
 954			     now, &node, foundname, rdataset, sigrdataset);
 955
 956	if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) {
 957		if (dns_rdataset_isassociated(rdataset))
 958			dns_rdataset_disassociate(rdataset);
 959		if (sigrdataset != NULL &&
 960		    dns_rdataset_isassociated(sigrdataset))
 961			dns_rdataset_disassociate(sigrdataset);
 962		if (node != NULL)
 963			dns_db_detachnode(db, &node);
 964		if (!is_cache) {
 965			dns_db_detach(&db);
 966			if (view->cachedb != NULL && !is_staticstub_zone) {
 967				/*
 968				 * Either the answer is in the cache, or we
 969				 * don't know it.
 970				 * Note that if the result comes from a
 971				 * static-stub zone we stop the search here
 972				 * (see the function description in view.h).
 973				 */
 974				is_cache = ISC_TRUE;
 975				dns_db_attach(view->cachedb, &db);
 976				goto db_find;
 977			}
 978		} else {
 979			/*
 980			 * We don't have the data in the cache.  If we've got
 981			 * glue from the zone, use it.
 982			 */
 983			if (dns_rdataset_isassociated(&zrdataset)) {
 984				dns_rdataset_clone(&zrdataset, rdataset);
 985				if (sigrdataset != NULL &&
 986				    dns_rdataset_isassociated(&zsigrdataset))
 987					dns_rdataset_clone(&zsigrdataset,
 988							   sigrdataset);
 989				result = DNS_R_GLUE;
 990				if (db != NULL)
 991					dns_db_detach(&db);
 992				dns_db_attach(zdb, &db);
 993				dns_db_attachnode(db, znode, &node);
 994				goto cleanup;
 995			}
 996		}
 997		/*
 998		 * We don't know the answer.
 999		 */
1000		result = ISC_R_NOTFOUND;
1001	} else if (result == DNS_R_GLUE) {
1002		if (view->cachedb != NULL && !is_staticstub_zone) {
1003			/*
1004			 * We found an answer, but the cache may be better.
1005			 * Remember what we've got and go look in the cache.
1006			 */
1007			is_cache = ISC_TRUE;
1008			dns_rdataset_clone(rdataset, &zrdataset);
1009			dns_rdataset_disassociate(rdataset);
1010			if (sigrdataset != NULL &&
1011			    dns_rdataset_isassociated(sigrdataset)) {
1012				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1013				dns_rdataset_disassociate(sigrdataset);
1014			}
1015			dns_db_attach(db, &zdb);
1016			dns_db_attachnode(zdb, node, &znode);
1017			dns_db_detachnode(db, &node);
1018			dns_db_detach(&db);
1019			dns_db_attach(view->cachedb, &db);
1020			goto db_find;
1021		}
1022		/*
1023		 * Otherwise, the glue is the best answer.
1024		 */
1025		result = ISC_R_SUCCESS;
1026	}
1027
1028#ifdef BIND9
1029	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
1030		if (dns_rdataset_isassociated(rdataset))
1031			dns_rdataset_disassociate(rdataset);
1032		if (sigrdataset != NULL &&
1033		    dns_rdataset_isassociated(sigrdataset))
1034			dns_rdataset_disassociate(sigrdataset);
1035		if (db != NULL) {
1036			if (node != NULL)
1037				dns_db_detachnode(db, &node);
1038			dns_db_detach(&db);
1039		}
1040		result = dns_db_find(view->hints, name, NULL, type, options,
1041				     now, &node, foundname,
1042				     rdataset, sigrdataset);
1043		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
1044			/*
1045			 * We just used a hint.  Let the resolver know it
1046			 * should consider priming.
1047			 */
1048			dns_resolver_prime(view->resolver);
1049			dns_db_attach(view->hints, &db);
1050			result = DNS_R_HINT;
1051		} else if (result == DNS_R_NXRRSET) {
1052			dns_db_attach(view->hints, &db);
1053			result = DNS_R_HINTNXRRSET;
1054		} else if (result == DNS_R_NXDOMAIN)
1055			result = ISC_R_NOTFOUND;
1056
1057		/*
1058		 * Cleanup if non-standard hints are used.
1059		 */
1060		if (db == NULL && node != NULL)
1061			dns_db_detachnode(view->hints, &node);
1062	}
1063#endif /* BIND9 */
1064
1065 cleanup:
1066	if (dns_rdataset_isassociated(&zrdataset)) {
1067		dns_rdataset_disassociate(&zrdataset);
1068		if (dns_rdataset_isassociated(&zsigrdataset))
1069			dns_rdataset_disassociate(&zsigrdataset);
1070	}
1071
1072	if (zdb != NULL) {
1073		if (znode != NULL)
1074			dns_db_detachnode(zdb, &znode);
1075		dns_db_detach(&zdb);
1076	}
1077
1078	if (db != NULL) {
1079		if (node != NULL) {
1080			if (nodep != NULL)
1081				*nodep = node;
1082			else
1083				dns_db_detachnode(db, &node);
1084		}
1085		if (dbp != NULL)
1086			*dbp = db;
1087		else
1088			dns_db_detach(&db);
1089	} else
1090		INSIST(node == NULL);
1091
1092#ifdef BIND9
1093	if (zone != NULL)
1094		dns_zone_detach(&zone);
1095#endif
1096
1097	return (result);
1098}
1099
1100isc_result_t
1101dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1102		    isc_stdtime_t now, unsigned int options,
1103		    isc_boolean_t use_hints,
1104		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1105{
1106	isc_result_t result;
1107	dns_fixedname_t foundname;
1108
1109	dns_fixedname_init(&foundname);
1110	result = dns_view_find(view, name, type, now, options, use_hints,
1111			       NULL, NULL, dns_fixedname_name(&foundname),
1112			       rdataset, sigrdataset);
1113	if (result == DNS_R_NXDOMAIN) {
1114		/*
1115		 * The rdataset and sigrdataset of the relevant NSEC record
1116		 * may be returned, but the caller cannot use them because
1117		 * foundname is not returned by this simplified API.  We
1118		 * disassociate them here to prevent any misuse by the caller.
1119		 */
1120		if (dns_rdataset_isassociated(rdataset))
1121			dns_rdataset_disassociate(rdataset);
1122		if (sigrdataset != NULL &&
1123		    dns_rdataset_isassociated(sigrdataset))
1124			dns_rdataset_disassociate(sigrdataset);
1125	} else if (result != ISC_R_SUCCESS &&
1126		   result != DNS_R_GLUE &&
1127		   result != DNS_R_HINT &&
1128		   result != DNS_R_NCACHENXDOMAIN &&
1129		   result != DNS_R_NCACHENXRRSET &&
1130		   result != DNS_R_NXRRSET &&
1131		   result != DNS_R_HINTNXRRSET &&
1132		   result != ISC_R_NOTFOUND) {
1133		if (dns_rdataset_isassociated(rdataset))
1134			dns_rdataset_disassociate(rdataset);
1135		if (sigrdataset != NULL &&
1136		    dns_rdataset_isassociated(sigrdataset))
1137			dns_rdataset_disassociate(sigrdataset);
1138		result = ISC_R_NOTFOUND;
1139	}
1140
1141	return (result);
1142}
1143
1144isc_result_t
1145dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1146		     isc_stdtime_t now, unsigned int options,
1147		     isc_boolean_t use_hints,
1148		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1149{
1150	return(dns_view_findzonecut2(view, name, fname, now, options,
1151				     use_hints, ISC_TRUE,
1152				     rdataset, sigrdataset));
1153}
1154
1155isc_result_t
1156dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1157		      isc_stdtime_t now, unsigned int options,
1158		      isc_boolean_t use_hints,	isc_boolean_t use_cache,
1159		      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1160{
1161	isc_result_t result;
1162	dns_db_t *db;
1163	isc_boolean_t is_cache, use_zone, try_hints;
1164	dns_zone_t *zone;
1165	dns_name_t *zfname;
1166	dns_rdataset_t zrdataset, zsigrdataset;
1167	dns_fixedname_t zfixedname;
1168
1169	REQUIRE(DNS_VIEW_VALID(view));
1170	REQUIRE(view->frozen);
1171
1172	db = NULL;
1173	zone = NULL;
1174	use_zone = ISC_FALSE;
1175	try_hints = ISC_FALSE;
1176	zfname = NULL;
1177
1178	/*
1179	 * Initialize.
1180	 */
1181	dns_fixedname_init(&zfixedname);
1182	dns_rdataset_init(&zrdataset);
1183	dns_rdataset_init(&zsigrdataset);
1184
1185	/*
1186	 * Find the right database.
1187	 */
1188#ifdef BIND9
1189	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1190	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1191		result = dns_zone_getdb(zone, &db);
1192#else
1193	result = ISC_R_NOTFOUND;
1194#endif
1195	if (result == ISC_R_NOTFOUND) {
1196		/*
1197		 * We're not directly authoritative for this query name, nor
1198		 * is it a subdomain of any zone for which we're
1199		 * authoritative.
1200		 */
1201		if (use_cache && view->cachedb != NULL) {
1202			/*
1203			 * We have a cache; try it.
1204			 */
1205			dns_db_attach(view->cachedb, &db);
1206		} else {
1207			/*
1208			 * Maybe we have hints...
1209			 */
1210			try_hints = ISC_TRUE;
1211			goto finish;
1212		}
1213	} else if (result != ISC_R_SUCCESS) {
1214		/*
1215		 * Something is broken.
1216		 */
1217		goto cleanup;
1218	}
1219	is_cache = dns_db_iscache(db);
1220
1221 db_find:
1222	/*
1223	 * Look for the zonecut.
1224	 */
1225	if (!is_cache) {
1226		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1227				     now, NULL, fname, rdataset, sigrdataset);
1228		if (result == DNS_R_DELEGATION)
1229			result = ISC_R_SUCCESS;
1230		else if (result != ISC_R_SUCCESS)
1231			goto cleanup;
1232		if (use_cache && view->cachedb != NULL && db != view->hints) {
1233			/*
1234			 * We found an answer, but the cache may be better.
1235			 */
1236			zfname = dns_fixedname_name(&zfixedname);
1237			result = dns_name_copy(fname, zfname, NULL);
1238			if (result != ISC_R_SUCCESS)
1239				goto cleanup;
1240			dns_rdataset_clone(rdataset, &zrdataset);
1241			dns_rdataset_disassociate(rdataset);
1242			if (sigrdataset != NULL &&
1243			    dns_rdataset_isassociated(sigrdataset)) {
1244				dns_rdataset_clone(sigrdataset, &zsigrdataset);
1245				dns_rdataset_disassociate(sigrdataset);
1246			}
1247			dns_db_detach(&db);
1248			dns_db_attach(view->cachedb, &db);
1249			is_cache = ISC_TRUE;
1250			goto db_find;
1251		}
1252	} else {
1253		result = dns_db_findzonecut(db, name, options, now, NULL,
1254					    fname, rdataset, sigrdataset);
1255		if (result == ISC_R_SUCCESS) {
1256			if (zfname != NULL &&
1257			    (!dns_name_issubdomain(fname, zfname) ||
1258			     (dns_zone_staticstub &&
1259			      dns_name_equal(fname, zfname)))) {
1260				/*
1261				 * We found a zonecut in the cache, but our
1262				 * zone delegation is better.
1263				 */
1264				use_zone = ISC_TRUE;
1265			}
1266		} else if (result == ISC_R_NOTFOUND) {
1267			if (zfname != NULL) {
1268				/*
1269				 * We didn't find anything in the cache, but we
1270				 * have a zone delegation, so use it.
1271				 */
1272				use_zone = ISC_TRUE;
1273			} else {
1274				/*
1275				 * Maybe we have hints...
1276				 */
1277				try_hints = ISC_TRUE;
1278			}
1279		} else {
1280			/*
1281			 * Something bad happened.
1282			 */
1283			goto cleanup;
1284		}
1285	}
1286
1287 finish:
1288	if (use_zone) {
1289		if (dns_rdataset_isassociated(rdataset)) {
1290			dns_rdataset_disassociate(rdataset);
1291			if (sigrdataset != NULL &&
1292			    dns_rdataset_isassociated(sigrdataset))
1293				dns_rdataset_disassociate(sigrdataset);
1294		}
1295		result = dns_name_copy(zfname, fname, NULL);
1296		if (result != ISC_R_SUCCESS)
1297			goto cleanup;
1298		dns_rdataset_clone(&zrdataset, rdataset);
1299		if (sigrdataset != NULL &&
1300		    dns_rdataset_isassociated(&zrdataset))
1301			dns_rdataset_clone(&zsigrdataset, sigrdataset);
1302	} else if (try_hints && use_hints && view->hints != NULL) {
1303		/*
1304		 * We've found nothing so far, but we have hints.
1305		 */
1306		result = dns_db_find(view->hints, dns_rootname, NULL,
1307				     dns_rdatatype_ns, 0, now, NULL, fname,
1308				     rdataset, NULL);
1309		if (result != ISC_R_SUCCESS) {
1310			/*
1311			 * We can't even find the hints for the root
1312			 * nameservers!
1313			 */
1314			if (dns_rdataset_isassociated(rdataset))
1315				dns_rdataset_disassociate(rdataset);
1316			result = ISC_R_NOTFOUND;
1317		}
1318	}
1319
1320 cleanup:
1321	if (dns_rdataset_isassociated(&zrdataset)) {
1322		dns_rdataset_disassociate(&zrdataset);
1323		if (dns_rdataset_isassociated(&zsigrdataset))
1324			dns_rdataset_disassociate(&zsigrdataset);
1325	}
1326	if (db != NULL)
1327		dns_db_detach(&db);
1328#ifdef BIND9
1329	if (zone != NULL)
1330		dns_zone_detach(&zone);
1331#endif
1332
1333	return (result);
1334}
1335
1336isc_result_t
1337dns_viewlist_find(dns_viewlist_t *list, const char *name,
1338		  dns_rdataclass_t rdclass, dns_view_t **viewp)
1339{
1340	dns_view_t *view;
1341
1342	REQUIRE(list != NULL);
1343
1344	for (view = ISC_LIST_HEAD(*list);
1345	     view != NULL;
1346	     view = ISC_LIST_NEXT(view, link)) {
1347		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1348			break;
1349	}
1350	if (view == NULL)
1351		return (ISC_R_NOTFOUND);
1352
1353	dns_view_attach(view, viewp);
1354
1355	return (ISC_R_SUCCESS);
1356}
1357
1358#ifdef BIND9
1359isc_result_t
1360dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1361		      isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1362		      dns_zone_t **zonep)
1363{
1364	dns_view_t *view;
1365	isc_result_t result;
1366	dns_zone_t *zone1 = NULL, *zone2 = NULL;
1367	dns_zone_t **zp = NULL;;
1368
1369	REQUIRE(list != NULL);
1370	for (view = ISC_LIST_HEAD(*list);
1371	     view != NULL;
1372	     view = ISC_LIST_NEXT(view, link)) {
1373		if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1374			continue;
1375
1376		/*
1377		 * If the zone is defined in more than one view,
1378		 * treat it as not found.
1379		 */
1380		zp = (zone1 == NULL) ? &zone1 : &zone2;
1381		result = dns_zt_find(view->zonetable, name, 0, NULL, zp);
1382		INSIST(result == ISC_R_SUCCESS ||
1383		       result == ISC_R_NOTFOUND ||
1384		       result == DNS_R_PARTIALMATCH);
1385
1386		/* Treat a partial match as no match */
1387		if (result == DNS_R_PARTIALMATCH) {
1388			dns_zone_detach(zp);
1389			result = ISC_R_NOTFOUND;
1390			POST(result);
1391		}
1392
1393		if (zone2 != NULL) {
1394			dns_zone_detach(&zone1);
1395			dns_zone_detach(&zone2);
1396			return (ISC_R_NOTFOUND);
1397		}
1398	}
1399
1400	if (zone1 != NULL) {
1401		dns_zone_attach(zone1, zonep);
1402		dns_zone_detach(&zone1);
1403		return (ISC_R_SUCCESS);
1404	}
1405
1406	return (ISC_R_NOTFOUND);
1407}
1408
1409isc_result_t
1410dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1411
1412	REQUIRE(DNS_VIEW_VALID(view));
1413
1414	return (dns_zt_load(view->zonetable, stop));
1415}
1416
1417isc_result_t
1418dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1419
1420	REQUIRE(DNS_VIEW_VALID(view));
1421
1422	return (dns_zt_loadnew(view->zonetable, stop));
1423}
1424#endif /* BIND9 */
1425
1426isc_result_t
1427dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1428{
1429	isc_result_t result;
1430	REQUIRE(keyp != NULL && *keyp == NULL);
1431
1432	result = dns_tsigkey_find(keyp, keyname, NULL,
1433				  view->statickeys);
1434	if (result == ISC_R_NOTFOUND)
1435		result = dns_tsigkey_find(keyp, keyname, NULL,
1436					  view->dynamickeys);
1437	return (result);
1438}
1439
1440isc_result_t
1441dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1442		     dns_tsigkey_t **keyp)
1443{
1444	isc_result_t result;
1445	dns_name_t *keyname = NULL;
1446	dns_peer_t *peer = NULL;
1447
1448	result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1449	if (result != ISC_R_SUCCESS)
1450		return (result);
1451
1452	result = dns_peer_getkey(peer, &keyname);
1453	if (result != ISC_R_SUCCESS)
1454		return (result);
1455
1456	result = dns_view_gettsig(view, keyname, keyp);
1457	return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1458}
1459
1460isc_result_t
1461dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1462	REQUIRE(DNS_VIEW_VALID(view));
1463	REQUIRE(source != NULL);
1464
1465	return (dns_tsig_verify(source, msg, view->statickeys,
1466				view->dynamickeys));
1467}
1468
1469#ifdef BIND9
1470isc_result_t
1471dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1472	isc_result_t result;
1473
1474	REQUIRE(DNS_VIEW_VALID(view));
1475
1476	(void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1477	result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1478					 &dns_master_style_cache, fp);
1479	if (result != ISC_R_SUCCESS)
1480		return (result);
1481	dns_adb_dump(view->adb, fp);
1482	dns_resolver_printbadcache(view->resolver, fp);
1483	return (ISC_R_SUCCESS);
1484}
1485#endif
1486
1487isc_result_t
1488dns_view_flushcache(dns_view_t *view) {
1489	return (dns_view_flushcache2(view, ISC_FALSE));
1490}
1491
1492isc_result_t
1493dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1494	isc_result_t result;
1495
1496	REQUIRE(DNS_VIEW_VALID(view));
1497
1498	if (view->cachedb == NULL)
1499		return (ISC_R_SUCCESS);
1500	if (!fixuponly) {
1501		result = dns_cache_flush(view->cache);
1502		if (result != ISC_R_SUCCESS)
1503			return (result);
1504	}
1505#ifdef BIND9
1506	if (view->acache != NULL)
1507		dns_acache_putdb(view->acache, view->cachedb);
1508#endif
1509	dns_db_detach(&view->cachedb);
1510	dns_cache_attachdb(view->cache, &view->cachedb);
1511#ifdef BIND9
1512	if (view->acache != NULL)
1513		dns_acache_setdb(view->acache, view->cachedb);
1514	if (view->resolver != NULL)
1515		dns_resolver_flushbadcache(view->resolver, NULL);
1516#endif
1517
1518	dns_adb_flush(view->adb);
1519	return (ISC_R_SUCCESS);
1520}
1521
1522isc_result_t
1523dns_view_flushname(dns_view_t *view, dns_name_t *name) {
1524
1525	REQUIRE(DNS_VIEW_VALID(view));
1526
1527	if (view->adb != NULL)
1528		dns_adb_flushname(view->adb, name);
1529	if (view->cache == NULL)
1530		return (ISC_R_SUCCESS);
1531	if (view->resolver != NULL)
1532		dns_resolver_flushbadcache(view->resolver, name);
1533	return (dns_cache_flushname(view->cache, name));
1534}
1535
1536isc_result_t
1537dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1538	isc_result_t result;
1539	dns_name_t *new;
1540	isc_uint32_t hash;
1541
1542	REQUIRE(DNS_VIEW_VALID(view));
1543
1544	if (view->delonly == NULL) {
1545		view->delonly = isc_mem_get(view->mctx,
1546					    sizeof(dns_namelist_t) *
1547					    DNS_VIEW_DELONLYHASH);
1548		if (view->delonly == NULL)
1549			return (ISC_R_NOMEMORY);
1550		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1551			ISC_LIST_INIT(view->delonly[hash]);
1552	}
1553	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1554	new = ISC_LIST_HEAD(view->delonly[hash]);
1555	while (new != NULL && !dns_name_equal(new, name))
1556		new = ISC_LIST_NEXT(new, link);
1557	if (new != NULL)
1558		return (ISC_R_SUCCESS);
1559	new = isc_mem_get(view->mctx, sizeof(*new));
1560	if (new == NULL)
1561		return (ISC_R_NOMEMORY);
1562	dns_name_init(new, NULL);
1563	result = dns_name_dup(name, view->mctx, new);
1564	if (result == ISC_R_SUCCESS)
1565		ISC_LIST_APPEND(view->delonly[hash], new, link);
1566	else
1567		isc_mem_put(view->mctx, new, sizeof(*new));
1568	return (result);
1569}
1570
1571isc_result_t
1572dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1573	isc_result_t result;
1574	dns_name_t *new;
1575	isc_uint32_t hash;
1576
1577	REQUIRE(DNS_VIEW_VALID(view));
1578
1579	if (view->rootexclude == NULL) {
1580		view->rootexclude = isc_mem_get(view->mctx,
1581					    sizeof(dns_namelist_t) *
1582					    DNS_VIEW_DELONLYHASH);
1583		if (view->rootexclude == NULL)
1584			return (ISC_R_NOMEMORY);
1585		for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1586			ISC_LIST_INIT(view->rootexclude[hash]);
1587	}
1588	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1589	new = ISC_LIST_HEAD(view->rootexclude[hash]);
1590	while (new != NULL && !dns_name_equal(new, name))
1591		new = ISC_LIST_NEXT(new, link);
1592	if (new != NULL)
1593		return (ISC_R_SUCCESS);
1594	new = isc_mem_get(view->mctx, sizeof(*new));
1595	if (new == NULL)
1596		return (ISC_R_NOMEMORY);
1597	dns_name_init(new, NULL);
1598	result = dns_name_dup(name, view->mctx, new);
1599	if (result == ISC_R_SUCCESS)
1600		ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1601	else
1602		isc_mem_put(view->mctx, new, sizeof(*new));
1603	return (result);
1604}
1605
1606isc_boolean_t
1607dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1608	dns_name_t *new;
1609	isc_uint32_t hash;
1610
1611	REQUIRE(DNS_VIEW_VALID(view));
1612
1613	if (!view->rootdelonly && view->delonly == NULL)
1614		return (ISC_FALSE);
1615
1616	hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1617	if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1618		if (view->rootexclude == NULL)
1619			return (ISC_TRUE);
1620		new = ISC_LIST_HEAD(view->rootexclude[hash]);
1621		while (new != NULL && !dns_name_equal(new, name))
1622			new = ISC_LIST_NEXT(new, link);
1623		if (new == NULL)
1624			return (ISC_TRUE);
1625	}
1626
1627	if (view->delonly == NULL)
1628		return (ISC_FALSE);
1629
1630	new = ISC_LIST_HEAD(view->delonly[hash]);
1631	while (new != NULL && !dns_name_equal(new, name))
1632		new = ISC_LIST_NEXT(new, link);
1633	if (new == NULL)
1634		return (ISC_FALSE);
1635	return (ISC_TRUE);
1636}
1637
1638void
1639dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1640	REQUIRE(DNS_VIEW_VALID(view));
1641	view->rootdelonly = value;
1642}
1643
1644isc_boolean_t
1645dns_view_getrootdelonly(dns_view_t *view) {
1646	REQUIRE(DNS_VIEW_VALID(view));
1647	return (view->rootdelonly);
1648}
1649
1650#ifdef BIND9
1651isc_result_t
1652dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1653	REQUIRE(DNS_VIEW_VALID(view));
1654	return (dns_zt_freezezones(view->zonetable, value));
1655}
1656#endif
1657
1658void
1659dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1660	REQUIRE(DNS_VIEW_VALID(view));
1661	REQUIRE(!view->frozen);
1662	REQUIRE(view->resstats == NULL);
1663
1664	isc_stats_attach(stats, &view->resstats);
1665}
1666
1667void
1668dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1669	REQUIRE(DNS_VIEW_VALID(view));
1670	REQUIRE(statsp != NULL && *statsp == NULL);
1671
1672	if (view->resstats != NULL)
1673		isc_stats_attach(view->resstats, statsp);
1674}
1675
1676void
1677dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1678	REQUIRE(DNS_VIEW_VALID(view));
1679	REQUIRE(!view->frozen);
1680	REQUIRE(view->resquerystats == NULL);
1681
1682	dns_stats_attach(stats, &view->resquerystats);
1683}
1684
1685void
1686dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1687	REQUIRE(DNS_VIEW_VALID(view));
1688	REQUIRE(statsp != NULL && *statsp == NULL);
1689
1690	if (view->resquerystats != NULL)
1691		dns_stats_attach(view->resquerystats, statsp);
1692}
1693
1694isc_result_t
1695dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1696	REQUIRE(DNS_VIEW_VALID(view));
1697	if (view->secroots_priv != NULL)
1698		dns_keytable_detach(&view->secroots_priv);
1699	return (dns_keytable_create(mctx, &view->secroots_priv));
1700}
1701
1702isc_result_t
1703dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1704	REQUIRE(DNS_VIEW_VALID(view));
1705	REQUIRE(ktp != NULL && *ktp == NULL);
1706	if (view->secroots_priv == NULL)
1707		return (ISC_R_NOTFOUND);
1708	dns_keytable_attach(view->secroots_priv, ktp);
1709	return (ISC_R_SUCCESS);
1710}
1711
1712isc_result_t
1713dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1714			 isc_boolean_t *secure_domain) {
1715	REQUIRE(DNS_VIEW_VALID(view));
1716
1717	if (view->secroots_priv == NULL)
1718		return (ISC_R_NOTFOUND);
1719	return (dns_keytable_issecuredomain(view->secroots_priv, name,
1720					    secure_domain));
1721}
1722
1723void
1724dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1725		 dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1726{
1727	isc_result_t result;
1728	unsigned char data[4096];
1729	dns_rdata_t rdata = DNS_RDATA_INIT;
1730	isc_buffer_t buffer;
1731	dst_key_t *key = NULL;
1732	dns_keytable_t *sr = NULL;
1733
1734	/*
1735	 * Clear the revoke bit, if set, so that the key will match what's
1736	 * in secroots now.
1737	 */
1738	dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1739
1740	/* Convert dnskey to DST key. */
1741	isc_buffer_init(&buffer, data, sizeof(data));
1742	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1743			     dns_rdatatype_dnskey, dnskey, &buffer);
1744	result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1745	if (result != ISC_R_SUCCESS)
1746		return;
1747	result = dns_view_getsecroots(view, &sr);
1748	if (result == ISC_R_SUCCESS) {
1749		dns_keytable_deletekeynode(sr, key);
1750		dns_keytable_detach(&sr);
1751	}
1752	dst_key_free(&key);
1753}
1754
1755#define NZF ".nzf"
1756
1757void
1758dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1759		     void (*cfg_destroy)(void **))
1760{
1761	REQUIRE(DNS_VIEW_VALID(view));
1762	REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1763
1764#ifdef BIND9
1765	if (view->new_zone_file != NULL) {
1766		isc_mem_free(view->mctx, view->new_zone_file);
1767		view->new_zone_file = NULL;
1768	}
1769
1770	if (view->new_zone_config != NULL) {
1771		view->cfg_destroy(&view->new_zone_config);
1772		view->cfg_destroy = NULL;
1773	}
1774
1775	if (allow) {
1776		char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1777		isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1778		/* Truncate the hash at 16 chars; full length is overkill */
1779		isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1780		view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1781		view->new_zone_config = cfgctx;
1782		view->cfg_destroy = cfg_destroy;
1783	}
1784#else
1785	UNUSED(allow);
1786	UNUSED(cfgctx);
1787	UNUSED(cfg_destroy);
1788#endif
1789}