view.c 26.2 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
3
 *
Bob Halley's avatar
add  
Bob Halley committed
4 5 6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
7
 *
8 9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
add  
Bob Halley committed
16 17
 */

18
/* $Id: view.c,v 1.85 2000/11/10 03:16:20 gson Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Bob Halley's avatar
add  
Bob Halley committed
20 21
#include <config.h>

22
#include <isc/task.h>
23
#include <isc/string.h>		/* Required for HP/UX (and others?) */
Michael Graff's avatar
Michael Graff committed
24
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
25

26
#include <dns/acl.h>
Bob Halley's avatar
add adb  
Bob Halley committed
27
#include <dns/adb.h>
28
#include <dns/cache.h>
Bob Halley's avatar
Bob Halley committed
29
#include <dns/db.h>
30
#include <dns/events.h>
31
#include <dns/forward.h>
32
#include <dns/keytable.h>
33
#include <dns/master.h>
34
#include <dns/peer.h>
Bob Halley's avatar
Bob Halley committed
35
#include <dns/rdataset.h>
Mark Andrews's avatar
Mark Andrews committed
36
#include <dns/request.h>
37 38
#include <dns/resolver.h>
#include <dns/result.h>
Brian Wellington's avatar
Brian Wellington committed
39
#include <dns/tsig.h>
40
#include <dns/zone.h>
41
#include <dns/zt.h>
Bob Halley's avatar
add  
Bob Halley committed
42

43 44
#define RESSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
#define ADBSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
Mark Andrews's avatar
Mark Andrews committed
45
#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
46 47 48

static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
static void adb_shutdown(isc_task_t *task, isc_event_t *event);
Mark Andrews's avatar
Mark Andrews committed
49
static void req_shutdown(isc_task_t *task, isc_event_t *event);
50

Bob Halley's avatar
add  
Bob Halley committed
51
isc_result_t
52 53
dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
		const char *name, dns_view_t **viewp)
Bob Halley's avatar
add  
Bob Halley committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
{
	dns_view_t *view;
	isc_result_t result;

	/*
	 * Create a view.
	 */

	REQUIRE(name != NULL);
	REQUIRE(viewp != NULL && *viewp == NULL);

	view = isc_mem_get(mctx, sizeof *view);
	if (view == NULL)
		return (ISC_R_NOMEMORY);
	view->name = isc_mem_strdup(mctx, name);
	if (view->name == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup_view;
	}
	result = isc_mutex_init(&view->lock);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_mutex_init() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_name;
	}
81
	result = isc_rwlock_init(&view->conflock, 1, 1);
82 83 84 85 86 87 88
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_rwlock_init() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_mutex;
	}
89 90
	view->zonetable = NULL;
	result = dns_zt_create(mctx, rdclass, &view->zonetable);
Bob Halley's avatar
add  
Bob Halley committed
91 92
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
93
				 "dns_zt_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
94 95
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
96
		goto cleanup_rwlock;
Bob Halley's avatar
add  
Bob Halley committed
97
	}
Bob Halley's avatar
Bob Halley committed
98
	view->secroots = NULL;
99
	result = dns_keytable_create(mctx, &view->secroots);
Bob Halley's avatar
Bob Halley committed
100 101
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
102
				 "dns_keytable_create() failed: %s",
Bob Halley's avatar
Bob Halley committed
103 104
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
105
		goto cleanup_zt;
Bob Halley's avatar
Bob Halley committed
106
	}
107 108 109 110 111 112 113 114 115
	view->trustedkeys = NULL;
	result = dns_keytable_create(mctx, &view->trustedkeys);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "dns_keytable_create() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_secroots;
	}
116 117 118 119 120 121 122 123 124
	view->fwdtable = NULL;
	result = dns_fwdtable_create(mctx, &view->fwdtable);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "dns_fwdtable_create() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_trustedkeys;
	}
125

126
	view->cache = NULL;
Bob Halley's avatar
Bob Halley committed
127
	view->cachedb = NULL;
Bob Halley's avatar
Bob Halley committed
128
	view->hints = NULL;
Bob Halley's avatar
add  
Bob Halley committed
129
	view->resolver = NULL;
Bob Halley's avatar
add adb  
Bob Halley committed
130
	view->adb = NULL;
131
	view->loadmgr = NULL;
Mark Andrews's avatar
Mark Andrews committed
132
	view->requestmgr = NULL;
Bob Halley's avatar
add  
Bob Halley committed
133 134
	view->mctx = mctx;
	view->rdclass = rdclass;
Bob Halley's avatar
Bob Halley committed
135
	view->frozen = ISC_FALSE;
136
	view->task = NULL;
Bob Halley's avatar
add  
Bob Halley committed
137
	view->references = 1;
138
	view->weakrefs = 0;
Mark Andrews's avatar
Mark Andrews committed
139 140
	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
			    DNS_VIEWATTR_REQSHUTDOWN);
Brian Wellington's avatar
Brian Wellington committed
141 142
	view->statickeys = NULL;
	view->dynamickeys = NULL;
143
	view->matchclients = NULL;
144
	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
145
	if (result != ISC_R_SUCCESS)
146
		goto cleanup_fwdtable;
147
	view->peers = NULL;
148

149 150
	/*
	 * Initialize configuration data with default values.
151
	 */
152 153
	view->recursion = ISC_TRUE;
	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
Michael Graff's avatar
 
Michael Graff committed
154 155
	view->additionalfromcache = ISC_TRUE;
	view->additionalfromauth = ISC_TRUE;
156
	view->transfer_format = dns_one_answer;
157 158
	view->queryacl = NULL;
	view->recursionacl = NULL;
159
	view->sortlist = NULL;
160 161
	view->requestixfr = ISC_TRUE;
	view->provideixfr = ISC_TRUE;
162 163
	view->maxcachettl = 7 * 24 * 3600;
	view->maxncachettl = 3 * 3600;
164
	view->dstport = 53;
165

166
	result = dns_peerlist_new(view->mctx, &view->peers);
167
	if (result != ISC_R_SUCCESS)
168
		goto cleanup_dynkeys;
Michael Graff's avatar
Michael Graff committed
169
	ISC_LINK_INIT(view, link);
170 171 172 173 174 175
	ISC_EVENT_INIT(&view->resevent, sizeof view->resevent, 0, NULL,
		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
		       view, NULL, NULL, NULL);
	ISC_EVENT_INIT(&view->adbevent, sizeof view->adbevent, 0, NULL,
		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
		       view, NULL, NULL, NULL);
Mark Andrews's avatar
Mark Andrews committed
176 177 178
	ISC_EVENT_INIT(&view->reqevent, sizeof view->reqevent, 0, NULL,
		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
		       view, NULL, NULL, NULL);
Bob Halley's avatar
add  
Bob Halley committed
179
	view->magic = DNS_VIEW_MAGIC;
180

Bob Halley's avatar
add  
Bob Halley committed
181 182 183 184
	*viewp = view;

	return (ISC_R_SUCCESS);

185
 cleanup_dynkeys:
186
	dns_tsigkeyring_destroy(&view->dynamickeys);
187

188 189 190
 cleanup_fwdtable:
	dns_fwdtable_destroy(&view->fwdtable);

191 192 193
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

194
 cleanup_secroots:
195
	dns_keytable_detach(&view->secroots);
196

197 198
 cleanup_zt:
	dns_zt_detach(&view->zonetable);
Bob Halley's avatar
Bob Halley committed
199

200 201 202
 cleanup_rwlock:
	isc_rwlock_destroy(&view->conflock);

Bob Halley's avatar
add  
Bob Halley committed
203
 cleanup_mutex:
204
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
205 206 207 208 209 210 211 212 213 214 215 216 217

 cleanup_name:
	isc_mem_free(mctx, view->name);

 cleanup_view:
	isc_mem_put(mctx, view, sizeof *view);

	return (result);
}

static inline void
destroy(dns_view_t *view) {
	REQUIRE(!ISC_LINK_LINKED(view, link));
218
	REQUIRE(view->references == 0);
219
	REQUIRE(view->weakrefs == 0);
220 221
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
222
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
223

224 225
	if (view->peers != NULL)
		dns_peerlist_detach(&view->peers);
226
	if (view->dynamickeys != NULL)
227
		dns_tsigkeyring_destroy(&view->dynamickeys);
228
	if (view->statickeys != NULL)
229
		dns_tsigkeyring_destroy(&view->statickeys);
Bob Halley's avatar
add adb  
Bob Halley committed
230 231
	if (view->adb != NULL)
		dns_adb_detach(&view->adb);
Bob Halley's avatar
add  
Bob Halley committed
232 233
	if (view->resolver != NULL)
		dns_resolver_detach(&view->resolver);
234 235
	if (view->loadmgr != NULL)
		dns_loadmgr_detach(&view->loadmgr);
Mark Andrews's avatar
Mark Andrews committed
236 237
	if (view->requestmgr != NULL)
		dns_requestmgr_detach(&view->requestmgr);
238 239
	if (view->task != NULL)
		isc_task_detach(&view->task);
Bob Halley's avatar
Bob Halley committed
240 241
	if (view->hints != NULL)
		dns_db_detach(&view->hints);
Bob Halley's avatar
Bob Halley committed
242 243
	if (view->cachedb != NULL)
		dns_db_detach(&view->cachedb);
244 245
	if (view->cache != NULL)
		dns_cache_detach(&view->cache);
246 247
	if (view->matchclients != NULL)
		dns_acl_detach(&view->matchclients);
248 249 250 251
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
252 253
	if (view->sortlist != NULL)
		dns_acl_detach(&view->sortlist);
254 255
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
256
	dns_fwdtable_destroy(&view->fwdtable);
257
	isc_rwlock_destroy(&view->conflock);
258
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
259 260 261 262
	isc_mem_free(view->mctx, view->name);
	isc_mem_put(view->mctx, view, sizeof *view);
}

263 264 265 266
/*
 * Return true iff 'view' may be freed.
 * The caller must be holding the view lock.
 */
267 268 269
static isc_boolean_t
all_done(dns_view_t *view) {

270 271
	if (view->references == 0 && view->weakrefs == 0 &&
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
272 273 274 275 276
		return (ISC_TRUE);

	return (ISC_FALSE);
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

	REQUIRE(DNS_VIEW_VALID(source));
	REQUIRE(targetp != NULL && *targetp == NULL);

	LOCK(&source->lock);

	INSIST(source->references > 0);
	source->references++;
	INSIST(source->references != 0);

	UNLOCK(&source->lock);

	*targetp = source;
}

294 295
static void
view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
Bob Halley's avatar
add  
Bob Halley committed
296
	dns_view_t *view;
297
	isc_boolean_t done = ISC_FALSE;
Bob Halley's avatar
add  
Bob Halley committed
298 299 300 301 302 303 304 305 306

	REQUIRE(viewp != NULL);
	view = *viewp;
	REQUIRE(DNS_VIEW_VALID(view));

	LOCK(&view->lock);

	INSIST(view->references > 0);
	view->references--;
307 308 309 310 311
	if (view->references == 0) {
		if (!RESSHUTDOWN(view))
			dns_resolver_shutdown(view->resolver);
		if (!ADBSHUTDOWN(view))
			dns_adb_shutdown(view->adb);
Mark Andrews's avatar
Mark Andrews committed
312 313
		if (!REQSHUTDOWN(view))
			dns_requestmgr_shutdown(view->requestmgr);
314 315 316 317
		if (flush)
			dns_zt_flushanddetach(&view->zonetable);
		else
			dns_zt_detach(&view->zonetable);
318 319
		done = all_done(view);
	}
Bob Halley's avatar
add  
Bob Halley committed
320 321 322 323
	UNLOCK(&view->lock);

	*viewp = NULL;

324 325 326 327
	if (done)
		destroy(view);
}

328
void
329 330 331 332 333 334 335 336 337
dns_view_flushanddetach(dns_view_t **viewp) {
	view_flushanddetach(viewp, ISC_TRUE);
}

void
dns_view_detach(dns_view_t **viewp) {
	view_flushanddetach(viewp, ISC_FALSE);
}

Mark Andrews's avatar
Mark Andrews committed
338
static isc_result_t
339 340
dialup(dns_zone_t *zone, void *dummy) {
	UNUSED(dummy);
Mark Andrews's avatar
Mark Andrews committed
341 342 343 344 345 346 347 348 349 350
	dns_zone_dialup(zone);
	return (ISC_R_SUCCESS);
}

void
dns_view_dialup(dns_view_t *view) {
	REQUIRE(DNS_VIEW_VALID(view));
	dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
}

351
void
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {

	REQUIRE(DNS_VIEW_VALID(source));
	REQUIRE(targetp != NULL && *targetp == NULL);

	LOCK(&source->lock);
	source->weakrefs++;
	UNLOCK(&source->lock);

	*targetp = source;
}

void
dns_view_weakdetach(dns_view_t **viewp) {
	dns_view_t *view;
	isc_boolean_t done = ISC_FALSE;

	REQUIRE(viewp != NULL);
	view = *viewp;
	REQUIRE(DNS_VIEW_VALID(view));

	LOCK(&view->lock);

	INSIST(view->weakrefs > 0);
	view->weakrefs--;
	done = all_done(view);

	UNLOCK(&view->lock);

	*viewp = NULL;

	if (done)
		destroy(view);
}

387 388
static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
389
	dns_view_t *view = event->ev_arg;
390
	isc_boolean_t done;
391

392
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
393 394 395
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

396
	UNUSED(task);
397

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
	LOCK(&view->lock);

	view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
	done = all_done(view);

	UNLOCK(&view->lock);

	isc_event_free(&event);

	if (done)
		destroy(view);
}

static void
adb_shutdown(isc_task_t *task, isc_event_t *event) {
413
	dns_view_t *view = event->ev_arg;
414
	isc_boolean_t done;
415

416
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
417 418 419
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

420
	UNUSED(task);
421

422 423 424 425 426 427 428 429 430 431
	LOCK(&view->lock);

	view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
	done = all_done(view);

	UNLOCK(&view->lock);

	isc_event_free(&event);

	if (done)
Bob Halley's avatar
add  
Bob Halley committed
432 433
		destroy(view);
}
434

Mark Andrews's avatar
Mark Andrews committed
435 436 437 438
static void
req_shutdown(isc_task_t *task, isc_event_t *event) {
	dns_view_t *view = event->ev_arg;
	isc_boolean_t done;
439

Mark Andrews's avatar
Mark Andrews committed
440 441 442 443
	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

444
	UNUSED(task);
445

Mark Andrews's avatar
Mark Andrews committed
446 447 448 449 450 451 452 453 454 455 456 457 458
	LOCK(&view->lock);

	view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
	done = all_done(view);

	UNLOCK(&view->lock);

	isc_event_free(&event);

	if (done)
		destroy(view);
}

Bob Halley's avatar
Bob Halley committed
459
isc_result_t
Bob Halley's avatar
Bob Halley committed
460 461 462 463
dns_view_createresolver(dns_view_t *view,
			isc_taskmgr_t *taskmgr, unsigned int ntasks,
			isc_socketmgr_t *socketmgr,
			isc_timermgr_t *timermgr,
464
			unsigned int options,
465
			dns_dispatchmgr_t *dispatchmgr,
466 467
			dns_dispatch_t *dispatchv4,
			dns_dispatch_t *dispatchv6)
Bob Halley's avatar
Bob Halley committed
468
{
Bob Halley's avatar
add adb  
Bob Halley committed
469
	isc_result_t result;
470
	isc_event_t *event;
Bob Halley's avatar
add adb  
Bob Halley committed
471

472
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
473
	REQUIRE(!view->frozen);
474
	REQUIRE(view->resolver == NULL);
475

Bob Halley's avatar
Bob Halley committed
476
	result = isc_task_create(taskmgr, 0, &view->task);
477 478
	if (result != ISC_R_SUCCESS)
		return (result);
Bob Halley's avatar
Bob Halley committed
479
	isc_task_setname(view->task, "view", view);
480

Bob Halley's avatar
add adb  
Bob Halley committed
481
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
482 483
				     timermgr, options, dispatchmgr,
				     dispatchv4, dispatchv6,
484
				     &view->resolver);
485 486
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
487
		return (result);
488 489 490 491 492
	}
	event = &view->resevent;
	dns_resolver_whenshutdown(view->resolver, view->task, &event);
	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;

Bob Halley's avatar
add adb  
Bob Halley committed
493 494
	result = dns_adb_create(view->mctx, view, timermgr, taskmgr,
				&view->adb);
495 496 497 498 499 500 501
	if (result != ISC_R_SUCCESS) {
		dns_resolver_shutdown(view->resolver);
		return (result);
	}
	event = &view->adbevent;
	dns_adb_whenshutdown(view->adb, view->task, &event);
	view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
Bob Halley's avatar
add adb  
Bob Halley committed
502

Mark Andrews's avatar
Mark Andrews committed
503
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
David Lawrence's avatar
David Lawrence committed
504 505 506 507 508
				      dns_resolver_taskmgr(view->resolver),
				      dns_resolver_dispatchmgr(view->resolver),
				      dns_resolver_dispatchv4(view->resolver),
				      dns_resolver_dispatchv6(view->resolver),
				      &view->requestmgr);
Mark Andrews's avatar
Mark Andrews committed
509 510 511 512 513 514 515 516 517
	if (result != ISC_R_SUCCESS) {
		dns_adb_shutdown(view->adb);
		dns_resolver_shutdown(view->resolver);
		return (result);
	}
	event = &view->reqevent;
	dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
	view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;

518
	return (ISC_R_SUCCESS);
519 520 521
}

void
522
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
523
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
524
	REQUIRE(!view->frozen);
525

526
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
527
		dns_db_detach(&view->cachedb);
528 529 530 531 532
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
533 534
}

Bob Halley's avatar
Bob Halley committed
535 536 537 538 539 540 541 542 543 544
void
dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);
	REQUIRE(view->hints == NULL);
	REQUIRE(dns_db_iszone(hints));

	dns_db_attach(hints, &view->hints);
}

Brian Wellington's avatar
Brian Wellington committed
545 546 547 548
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
549
	if (view->statickeys != NULL)
550
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
551 552 553
	view->statickeys = ring;
}

554 555 556 557 558 559
void
dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
	REQUIRE(DNS_VIEW_VALID(view));
	view->dstport = dstport;
}

560 561 562 563 564 565 566 567 568
void
dns_view_setloadmgr(dns_view_t *view, dns_loadmgr_t *loadmgr) {
	REQUIRE(DNS_VIEW_VALID(view));

	if (view->loadmgr != NULL)
		dns_loadmgr_detach(&view->loadmgr);
	dns_loadmgr_attach(loadmgr, &view->loadmgr);
}

569
isc_result_t
570
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
571 572
	isc_result_t result;

573
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
574 575
	REQUIRE(!view->frozen);

576
	result = dns_zt_mount(view->zonetable, zone);
577

Bob Halley's avatar
Bob Halley committed
578
	return (result);
579 580 581 582
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
583 584 585
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

586 587
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
588
		dns_resolver_freeze(view->resolver);
589
	}
Bob Halley's avatar
Bob Halley committed
590 591 592
	view->frozen = ISC_TRUE;
}

593
isc_result_t
594
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
595 596 597 598
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
599
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
600
	if (result == DNS_R_PARTIALMATCH) {
601
		dns_zone_detach(zonep);
602
		result = ISC_R_NOTFOUND;
603
	}
604

605 606 607
	return (result);
}

Bob Halley's avatar
Bob Halley committed
608 609
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
610 611
	      isc_stdtime_t now, unsigned int options,
	      isc_boolean_t use_hints, dns_name_t *foundname,
Bob Halley's avatar
Bob Halley committed
612 613 614 615
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_db_t *db;
616
	isc_boolean_t is_cache;
Bob Halley's avatar
Bob Halley committed
617
	dns_rdataset_t zrdataset, zsigrdataset;
618
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
619 620 621 622 623 624

	/*
	 * Find an rdataset whose owner name is 'name', and whose type is
	 * 'type'.
	 */

625
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
626 627 628 629 630 631 632 633 634 635 636 637
	REQUIRE(view->frozen);
	REQUIRE(type != dns_rdatatype_any && type != dns_rdatatype_sig);

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);

	/*
	 * Find a database to answer the query.
	 */
638
	zone = NULL;
Bob Halley's avatar
Bob Halley committed
639
	db = NULL;
Bob Halley's avatar
Bob Halley committed
640
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
641 642
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
		result = dns_zone_getdb(zone, &db);
643
		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
644
			dns_db_attach(view->cachedb, &db);
645
		else if (result != ISC_R_SUCCESS)
646 647
			goto cleanup;
	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
Bob Halley's avatar
Bob Halley committed
648
		dns_db_attach(view->cachedb, &db);
649
	else
Bob Halley's avatar
Bob Halley committed
650 651
		goto cleanup;

652
	is_cache = dns_db_iscache(db);
653

Bob Halley's avatar
Bob Halley committed
654 655 656 657 658
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
659
			     now, NULL, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
660 661

	if (result == DNS_R_DELEGATION ||
662
	    result == ISC_R_NOTFOUND) {
663
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
664
			dns_rdataset_disassociate(rdataset);
665 666
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
667
			dns_rdataset_disassociate(sigrdataset);
668
		if (!is_cache) {
Bob Halley's avatar
Bob Halley committed
669 670 671 672 673
			if (view->cachedb != NULL) {
				/*
				 * Either the answer is in the cache, or we
				 * don't know it.
				 */
674
				is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
675 676 677 678 679 680 681 682 683
				dns_db_detach(&db);
				dns_db_attach(view->cachedb, &db);
				goto db_find;
			}
		} else {
			/*
			 * We don't have the data in the cache.  If we've got
			 * glue from the zone, use it.
			 */
684
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
685
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
686
				if (sigrdataset != NULL &&
687
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
688 689 690 691 692 693 694 695 696
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
697
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
698 699 700 701 702 703
	} else if (result == DNS_R_GLUE) {
		if (view->cachedb != NULL) {
			/*
			 * We found an answer, but the cache may be better.
			 * Remember what we've got and go look in the cache.
			 */
704
			is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
705 706
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
707
			if (sigrdataset != NULL &&
708
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
709 710 711 712 713 714 715 716 717 718 719
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			dns_db_detach(&db);
			dns_db_attach(view->cachedb, &db);
			goto db_find;
		}
		/*
		 * Otherwise, the glue is the best answer.
		 */
		result = ISC_R_SUCCESS;
Bob Halley's avatar
Bob Halley committed
720 721
	}

722
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
723
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
724
			dns_rdataset_disassociate(rdataset);
725 726
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
727 728
			dns_rdataset_disassociate(sigrdataset);
		result = dns_db_find(view->hints, name, NULL, type, options,
729
				     now, NULL, foundname,
Bob Halley's avatar
Bob Halley committed
730
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
731 732 733 734 735 736
		if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
			/*
			 * We just used a hint.  Let the resolver know it
			 * should consider priming.
			 */
			dns_resolver_prime(view->resolver);
Bob Halley's avatar
Bob Halley committed
737
			result = DNS_R_HINT;
Bob Halley's avatar
Bob Halley committed
738
		} else if (result == DNS_R_NXDOMAIN ||
739 740
			   result == DNS_R_NXRRSET)
			result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
741
	}
Bob Halley's avatar
Bob Halley committed
742 743

 cleanup:
744 745 746 747
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
748
		if (dns_rdataset_isassociated(rdataset))
749
			dns_rdataset_disassociate(rdataset);
750 751
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
752 753
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
754

755
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
756
		dns_rdataset_disassociate(&zrdataset);
757
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
758 759 760 761
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
762 763
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
764 765

	return (result);
766
}
767

768 769 770 771 772 773 774 775 776 777 778 779 780
isc_result_t
dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
		    isc_stdtime_t now, unsigned int options,
		    isc_boolean_t use_hints,
		    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_fixedname_t foundname;

	dns_fixedname_init(&foundname);
	result = dns_view_find(view, name, type, now, options, use_hints,
			       dns_fixedname_name(&foundname),
			       rdataset, sigrdataset);
781 782 783 784 785 786 787
	if (result == DNS_R_NXDOMAIN) {
		/*
		 * The rdataset and sigrdataset of the relevant NXT record
		 * may be returned, but the caller cannot use them because
		 * foundname is not returned by this simplified API.  We
		 * disassociate them here to prevent any misuse by the caller.
		 */
788
		if (dns_rdataset_isassociated(rdataset))
789
			dns_rdataset_disassociate(rdataset);
790 791
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
792 793 794 795 796 797 798
			dns_rdataset_disassociate(sigrdataset);
	} else if (result != ISC_R_SUCCESS &&
		   result != DNS_R_GLUE &&
		   result != DNS_R_HINT &&
		   result != DNS_R_NCACHENXDOMAIN &&
		   result != DNS_R_NCACHENXRRSET &&
		   result != DNS_R_NXRRSET &&
799
		   result != ISC_R_NOTFOUND) {
800
		if (dns_rdataset_isassociated(rdataset))
801
			dns_rdataset_disassociate(rdataset);
802 803
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
804
			dns_rdataset_disassociate(sigrdataset);
805
		result = ISC_R_NOTFOUND;
806 807 808 809 810
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
811 812 813 814 815 816 817 818
isc_result_t
dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
		     isc_stdtime_t now, unsigned int options,
		     isc_boolean_t use_hints,
		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_db_t *db;
819
	isc_boolean_t is_cache, use_zone, try_hints;
Bob Halley's avatar
Bob Halley committed
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
	dns_zone_t *zone;
	dns_name_t *zfname;
	dns_rdataset_t zrdataset, zsigrdataset;
	dns_fixedname_t zfixedname;

	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->frozen);

	db = NULL;
	zone = NULL;
	use_zone = ISC_FALSE;
	try_hints = ISC_FALSE;
	zfname = NULL;

	/*
	 * Initialize.
	 */
	dns_fixedname_init(&zfixedname);
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);

	/*
	 * Find the right database.
	 */
Bob Halley's avatar
Bob Halley committed
844
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
845
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
		result = dns_zone_getdb(zone, &db);
	if (result == ISC_R_NOTFOUND) {
		/*
		 * We're not directly authoritative for this query name, nor
		 * is it a subdomain of any zone for which we're
		 * authoritative.
		 */
		if (view->cachedb != NULL) {
			/*
			 * We have a cache; try it.
			 */
			dns_db_attach(view->cachedb, &db);
		} else {
			/*
			 * Maybe we have hints...
			 */
			try_hints = ISC_TRUE;
			goto finish;
		}
	} else if (result != ISC_R_SUCCESS) {
		/*
		 * Something is broken.
		 */
		goto cleanup;
	}
871
	is_cache = dns_db_iscache(db);
Bob Halley's avatar
Bob Halley committed
872 873 874 875 876

 db_find:
	/*
	 * Look for the zonecut.
	 */
877
	if (!is_cache) {
Bob Halley's avatar
Bob Halley committed
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
				     now, NULL, fname, rdataset, sigrdataset);
		if (result == DNS_R_DELEGATION)
			result = ISC_R_SUCCESS;
		else if (result != ISC_R_SUCCESS)
			goto cleanup;
		if (view->cachedb != NULL && db != view->hints) {
			/*
			 * We found an answer, but the cache may be better.
			 */
			zfname = dns_fixedname_name(&zfixedname);
			result = dns_name_concatenate(fname, NULL, zfname,
						      NULL);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
896
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
897 898 899 900 901
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			dns_db_detach(&db);
			dns_db_attach(view->cachedb, &db);
902
			is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939
			goto db_find;
		}
	} else {
		result = dns_db_findzonecut(db, name, options, now, NULL,
					    fname, rdataset, sigrdataset);
		if (result == ISC_R_SUCCESS) {
			if (zfname != NULL &&
			    !dns_name_issubdomain(fname, zfname)) {
				/*
				 * We found a zonecut in the cache, but our
				 * zone delegation is better.
				 */
				use_zone = ISC_TRUE;
			}
		} else if (result == ISC_R_NOTFOUND) {
			if (zfname != NULL) {
				/*
				 * We didn't find anything in the cache, but we
				 * have a zone delegation, so use it.
				 */
				use_zone = ISC_TRUE;
			} else {
				/*
				 * Maybe we have hints...
				 */
				try_hints = ISC_TRUE;
			}
		} else {
			/*
			 * Something bad happened.
			 */
			goto cleanup;
		}
	}

 finish:
	if (use_zone) {
940
		if (dns_rdataset_isassociated(rdataset)) {
Bob Halley's avatar
Bob Halley committed
941 942
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
943
			    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
944 945 946 947 948 949
				dns_rdataset_disassociate(sigrdataset);
		}
		result = dns_name_concatenate(zfname, NULL, fname, NULL);
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		dns_rdataset_clone(&zrdataset, rdataset);
950 951
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(&zrdataset))
Bob Halley's avatar
Bob Halley committed
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
			dns_rdataset_clone(&zsigrdataset, sigrdataset);
	} else if (try_hints && use_hints && view->hints != NULL) {
		/*
		 * We've found nothing so far, but we have hints.
		 */
		result = dns_db_find(view->hints, dns_rootname, NULL,
				     dns_rdatatype_ns, 0, now, NULL, fname,
				     rdataset, NULL);
		if (result != ISC_R_SUCCESS) {
			/*
			 * We can't even find the hints for the root
			 * nameservers!
			 */
			result = ISC_R_NOTFOUND;
		}
	}

 cleanup:
970
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
971
		dns_rdataset_disassociate(&zrdataset);
972
		if (dns_rdataset_isassociated(&zsigrdataset))