view.c 28.6 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
Brian Wellington's avatar
Brian Wellington committed
2
 * Copyright (C) 1999-2001  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.108 2001/11/27 04:06:14 marka 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/masterdump.h>
35
#include <dns/peer.h>
Bob Halley's avatar
Bob Halley committed
36
#include <dns/rdataset.h>
Mark Andrews's avatar
Mark Andrews committed
37
#include <dns/request.h>
38 39
#include <dns/resolver.h>
#include <dns/result.h>
Brian Wellington's avatar
Brian Wellington committed
40
#include <dns/tsig.h>
41
#include <dns/zone.h>
42
#include <dns/zt.h>
Bob Halley's avatar
add  
Bob Halley committed
43

44 45
#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
46
#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
47 48 49

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
50
static void req_shutdown(isc_task_t *task, isc_event_t *event);
51

Bob Halley's avatar
add  
Bob Halley committed
52
isc_result_t
53 54
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
55 56 57 58 59 60 61 62 63 64 65
{
	dns_view_t *view;
	isc_result_t result;

	/*
	 * Create a view.
	 */

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

Andreas Gustafsson's avatar
Andreas Gustafsson committed
66
	view = isc_mem_get(mctx, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
	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;
	}
82 83
	view->zonetable = NULL;
	result = dns_zt_create(mctx, rdclass, &view->zonetable);
Bob Halley's avatar
add  
Bob Halley committed
84 85
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
86
				 "dns_zt_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
87 88
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
89
		goto cleanup_mutex;
Bob Halley's avatar
add  
Bob Halley committed
90
	}
Bob Halley's avatar
Bob Halley committed
91
	view->secroots = NULL;
92
	result = dns_keytable_create(mctx, &view->secroots);
Bob Halley's avatar
Bob Halley committed
93 94
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
95
				 "dns_keytable_create() failed: %s",
Bob Halley's avatar
Bob Halley committed
96 97
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
98
		goto cleanup_zt;
Bob Halley's avatar
Bob Halley committed
99
	}
100 101 102 103 104 105 106 107 108
	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;
	}
109 110 111 112 113 114 115 116 117
	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;
	}
118

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

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

162
	result = dns_peerlist_new(view->mctx, &view->peers);
163
	if (result != ISC_R_SUCCESS)
164
		goto cleanup_dynkeys;
165 166 167 168 169

	result = dns_aclenv_init(view->mctx, &view->aclenv);
	if (result != ISC_R_SUCCESS)
		goto cleanup_peerlist;

Michael Graff's avatar
Michael Graff committed
170
	ISC_LINK_INIT(view, link);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
171
	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
172 173
		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
		       view, NULL, NULL, NULL);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
174
	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
175 176
		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
		       view, NULL, NULL, NULL);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
177
	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
Mark Andrews's avatar
Mark Andrews committed
178 179
		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
		       view, NULL, NULL, NULL);
Bob Halley's avatar
add  
Bob Halley committed
180
	view->magic = DNS_VIEW_MAGIC;
181

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

	return (ISC_R_SUCCESS);

186 187 188
 cleanup_peerlist:
	dns_peerlist_detach(&view->peers);

189
 cleanup_dynkeys:
190
	dns_tsigkeyring_destroy(&view->dynamickeys);
191

192 193 194
 cleanup_fwdtable:
	dns_fwdtable_destroy(&view->fwdtable);

195 196 197
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

198
 cleanup_secroots:
199
	dns_keytable_detach(&view->secroots);
200

201 202
 cleanup_zt:
	dns_zt_detach(&view->zonetable);
Bob Halley's avatar
Bob Halley committed
203

Bob Halley's avatar
add  
Bob Halley committed
204
 cleanup_mutex:
205
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
206 207 208 209 210

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

 cleanup_view:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
211
	isc_mem_put(mctx, view, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
212 213 214 215 216 217 218

	return (result);
}

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

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

267 268 269 270
/*
 * Return true iff 'view' may be freed.
 * The caller must be holding the view lock.
 */
271 272 273
static isc_boolean_t
all_done(dns_view_t *view) {

274 275
	if (isc_refcount_current(&view->references) == 0 &&
	    view->weakrefs == 0 &&
276
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
277 278 279 280 281
		return (ISC_TRUE);

	return (ISC_FALSE);
}

282 283 284 285 286 287
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

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

288
	isc_refcount_increment(&source->references, NULL);
289 290 291 292

	*targetp = source;
}

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

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

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

	*viewp = NULL;

322 323 324 325
	if (done)
		destroy(view);
}

326
void
327 328 329 330 331 332 333 334 335
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
336
static isc_result_t
337 338
dialup(dns_zone_t *zone, void *dummy) {
	UNUSED(dummy);
Mark Andrews's avatar
Mark Andrews committed
339 340 341 342 343 344 345 346 347 348
	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);
}

349
void
350 351 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
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);
}

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

390
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
391 392 393
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

394
	UNUSED(task);
395

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
	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) {
411
	dns_view_t *view = event->ev_arg;
412
	isc_boolean_t done;
413

414
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
415 416 417
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

418
	UNUSED(task);
419

420 421 422 423 424 425 426 427 428 429
	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
430 431
		destroy(view);
}
432

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

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

442
	UNUSED(task);
443

Mark Andrews's avatar
Mark Andrews committed
444 445 446 447 448 449 450 451 452 453 454 455 456
	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
457
isc_result_t
Bob Halley's avatar
Bob Halley committed
458 459 460 461
dns_view_createresolver(dns_view_t *view,
			isc_taskmgr_t *taskmgr, unsigned int ntasks,
			isc_socketmgr_t *socketmgr,
			isc_timermgr_t *timermgr,
462
			unsigned int options,
463
			dns_dispatchmgr_t *dispatchmgr,
464 465
			dns_dispatch_t *dispatchv4,
			dns_dispatch_t *dispatchv6)
Bob Halley's avatar
Bob Halley committed
466
{
Bob Halley's avatar
add adb  
Bob Halley committed
467
	isc_result_t result;
468
	isc_event_t *event;
469
	isc_mem_t *mctx = NULL;
Bob Halley's avatar
add adb  
Bob Halley committed
470

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

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

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

492 493 494
	isc_mem_create(0, 0, &mctx);
	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
	isc_mem_detach(&mctx);
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
isc_result_t
561
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
562 563
	isc_result_t result;

564
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
565 566
	REQUIRE(!view->frozen);

567
	result = dns_zt_mount(view->zonetable, zone);
568

Bob Halley's avatar
Bob Halley committed
569
	return (result);
570 571 572 573
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
574 575 576
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

577 578
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
579
		dns_resolver_freeze(view->resolver);
580
	}
Bob Halley's avatar
Bob Halley committed
581 582 583
	view->frozen = ISC_TRUE;
}

584
isc_result_t
585
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
586 587 588 589
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
590
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
591
	if (result == DNS_R_PARTIALMATCH) {
592
		dns_zone_detach(zonep);
593
		result = ISC_R_NOTFOUND;
594
	}
595

596 597 598
	return (result);
}

Bob Halley's avatar
Bob Halley committed
599 600
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
601 602
	      isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
	      dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
Bob Halley's avatar
Bob Halley committed
603 604 605
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
606 607
	dns_db_t *db, *zdb;
	dns_dbnode_t *node, *znode;
608
	isc_boolean_t is_cache;
Bob Halley's avatar
Bob Halley committed
609
	dns_rdataset_t zrdataset, zsigrdataset;
610
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
611 612 613 614 615 616

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

617
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
618
	REQUIRE(view->frozen);
619 620
	REQUIRE(type != dns_rdatatype_sig);
	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
Bob Halley's avatar
Bob Halley committed
621 622 623 624 625 626

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);
627 628
	zdb = NULL;
	znode = NULL;
Bob Halley's avatar
Bob Halley committed
629 630 631 632

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

648
	is_cache = dns_db_iscache(db);
649

Bob Halley's avatar
Bob Halley committed
650 651 652 653 654
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
655
			     now, &node, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
656 657

	if (result == DNS_R_DELEGATION ||
658
	    result == ISC_R_NOTFOUND) {
659
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
660
			dns_rdataset_disassociate(rdataset);
661 662
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
663
			dns_rdataset_disassociate(sigrdataset);
664 665
		if (node != NULL)
			dns_db_detachnode(db, &node);
666
		if (!is_cache) {
667
			dns_db_detach(&db);
Bob Halley's avatar
Bob Halley committed
668 669 670 671 672
			if (view->cachedb != NULL) {
				/*
				 * Either the answer is in the cache, or we
				 * don't know it.
				 */
673
				is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
674 675 676 677 678 679 680 681
				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.
			 */
682
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
683
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
684
				if (sigrdataset != NULL &&
685
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
686 687 688
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
689 690 691 692
				if (db != NULL)
					dns_db_detach(&db);
				dns_db_attach(zdb, &db);
				dns_db_attachnode(db, znode, &node);
Bob Halley's avatar
Bob Halley committed
693 694 695 696 697 698
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
699
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
700 701 702 703 704 705
	} 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.
			 */
706
			is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
707 708
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
709
			if (sigrdataset != NULL &&
710
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
711 712 713
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
714 715 716
			dns_db_attach(db, &zdb);
			dns_db_attachnode(zdb, node, &znode);
			dns_db_detachnode(db, &node);
Bob Halley's avatar
Bob Halley committed
717 718 719 720 721 722 723 724
			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
725 726
	}

727
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
728
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
729
			dns_rdataset_disassociate(rdataset);
730 731
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
732
			dns_rdataset_disassociate(sigrdataset);
733 734 735 736 737
		if (db != NULL) {
			if (node != NULL)
				dns_db_detachnode(db, &node);
			dns_db_detach(&db);
		}
Bob Halley's avatar
Bob Halley committed
738
		result = dns_db_find(view->hints, name, NULL, type, options,
739
				     now, &node, foundname,
Bob Halley's avatar
Bob Halley committed
740
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
741 742 743 744 745 746
		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);
747
			dns_db_attach(view->hints, &db);
Bob Halley's avatar
Bob Halley committed
748
			result = DNS_R_HINT;
749 750 751 752
		} else if (result == DNS_R_NXRRSET) {
			dns_db_attach(view->hints, &db);
			result = DNS_R_HINTNXRRSET;
		} else if (result == DNS_R_NXDOMAIN)
753
			result = ISC_R_NOTFOUND;
754 755 756 757 758 759

		/*
		 * Cleanup if non-standard hints are used.
		 */
		if (db == NULL && node != NULL)
			dns_db_detachnode(view->hints, &node);
Bob Halley's avatar
Bob Halley committed
760
	}
Bob Halley's avatar
Bob Halley committed
761 762

 cleanup:
763 764 765 766
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
767
		if (dns_rdataset_isassociated(rdataset))
768
			dns_rdataset_disassociate(rdataset);
769 770
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
771 772
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
773

774
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
775
		dns_rdataset_disassociate(&zrdataset);
776
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
777 778
			dns_rdataset_disassociate(&zsigrdataset);
	}
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796

	if (zdb != NULL) {
		if (znode != NULL)
			dns_db_detachnode(zdb, &znode);
		dns_db_detach(&zdb);
	}

	if (db != NULL) {
		if (node != NULL) {
			if (nodep != NULL)
				*nodep = node;
			else
				dns_db_detachnode(db, &node);
		}
		if (dbp != NULL)
			*dbp = db;
		else
			dns_db_detach(&db);
797 798
	} else
		INSIST(node == NULL);
799

800 801
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
802 803

	return (result);
804
}
805

806 807 808 809 810 811 812 813 814 815 816
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,
817
			       NULL, NULL, dns_fixedname_name(&foundname),
818
			       rdataset, sigrdataset);
819 820 821 822 823 824 825
	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.
		 */
826
		if (dns_rdataset_isassociated(rdataset))
827
			dns_rdataset_disassociate(rdataset);
828 829
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
830 831 832 833 834 835 836
			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 &&
837
		   result != DNS_R_HINTNXRRSET &&
838
		   result != ISC_R_NOTFOUND) {
839
		if (dns_rdataset_isassociated(rdataset))
840
			dns_rdataset_disassociate(rdataset);
841 842
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
843
			dns_rdataset_disassociate(sigrdataset);
844
		result = ISC_R_NOTFOUND;
845 846 847 848 849
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
850 851 852 853 854 855 856 857
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;
858
	isc_boolean_t is_cache, use_zone, try_hints;
Bob Halley's avatar
Bob Halley committed
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
	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
883
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);