view.c 27.9 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.100 2001/05/07 23:34:04 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/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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
{
	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;
	}
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
	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
137
	if (result != ISC_R_SUCCESS)
138
		goto cleanup_fwdtable;
139
	view->peers = NULL;
140

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

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

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

Michael Graff's avatar
Michael Graff committed
168
	ISC_LINK_INIT(view, link);
169 170 171 172 173 174
	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
175 176 177
	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
178
	view->magic = DNS_VIEW_MAGIC;
179

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

	return (ISC_R_SUCCESS);

184 185 186
 cleanup_peerlist:
	dns_peerlist_detach(&view->peers);

187
 cleanup_dynkeys:
188
	dns_tsigkeyring_destroy(&view->dynamickeys);
189

190 191 192
 cleanup_fwdtable:
	dns_fwdtable_destroy(&view->fwdtable);

193 194 195
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

196
 cleanup_secroots:
197
	dns_keytable_detach(&view->secroots);
198

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

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

 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));
217
	REQUIRE(isc_refcount_current(&view->references) == 0);
218
	REQUIRE(view->weakrefs == 0);
219 220
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
221
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
222

223 224
	if (view->peers != NULL)
		dns_peerlist_detach(&view->peers);
225
	if (view->dynamickeys != NULL)
226
		dns_tsigkeyring_destroy(&view->dynamickeys);
227
	if (view->statickeys != NULL)
228
		dns_tsigkeyring_destroy(&view->statickeys);
Bob Halley's avatar
add adb  
Bob Halley committed
229 230
	if (view->adb != NULL)
		dns_adb_detach(&view->adb);
Bob Halley's avatar
add  
Bob Halley committed
231 232
	if (view->resolver != NULL)
		dns_resolver_detach(&view->resolver);
Mark Andrews's avatar
Mark Andrews committed
233 234
	if (view->requestmgr != NULL)
		dns_requestmgr_detach(&view->requestmgr);
235 236
	if (view->task != NULL)
		isc_task_detach(&view->task);
Bob Halley's avatar
Bob Halley committed
237 238
	if (view->hints != NULL)
		dns_db_detach(&view->hints);
Bob Halley's avatar
Bob Halley committed
239 240
	if (view->cachedb != NULL)
		dns_db_detach(&view->cachedb);
241 242
	if (view->cache != NULL)
		dns_cache_detach(&view->cache);
243 244
	if (view->matchclients != NULL)
		dns_acl_detach(&view->matchclients);
245 246 247 248
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
249 250
	if (view->v6synthesisacl != NULL)
		dns_acl_detach(&view->v6synthesisacl);
251 252
	if (view->sortlist != NULL)
		dns_acl_detach(&view->sortlist);
253 254
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
255
	dns_fwdtable_destroy(&view->fwdtable);
256
	dns_aclenv_destroy(&view->aclenv);
257
	DESTROYLOCK(&view->lock);
258
	isc_refcount_destroy(&view->references);
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 (isc_refcount_current(&view->references) == 0 &&
	    view->weakrefs == 0 &&
272
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
273 274 275 276 277
		return (ISC_TRUE);

	return (ISC_FALSE);
}

278 279 280 281 282 283
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

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

284
	isc_refcount_increment(&source->references, NULL);
285 286 287 288

	*targetp = source;
}

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

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

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

	*viewp = NULL;

318 319 320 321
	if (done)
		destroy(view);
}

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

345
void
346 347 348 349 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
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);
}

381 382
static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
383
	dns_view_t *view = event->ev_arg;
384
	isc_boolean_t done;
385

386
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
387 388 389
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

390
	UNUSED(task);
391

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

410
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
411 412 413
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

414
	UNUSED(task);
415

416 417 418 419 420 421 422 423 424 425
	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
426 427
		destroy(view);
}
428

Mark Andrews's avatar
Mark Andrews committed
429 430 431 432
static void
req_shutdown(isc_task_t *task, isc_event_t *event) {
	dns_view_t *view = event->ev_arg;
	isc_boolean_t done;
433

Mark Andrews's avatar
Mark Andrews committed
434 435 436 437
	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

438
	UNUSED(task);
439

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

466
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
467
	REQUIRE(!view->frozen);
468
	REQUIRE(view->resolver == NULL);
469

Bob Halley's avatar
Bob Halley committed
470
	result = isc_task_create(taskmgr, 0, &view->task);
471 472
	if (result != ISC_R_SUCCESS)
		return (result);
Bob Halley's avatar
Bob Halley committed
473
	isc_task_setname(view->task, "view", view);
474

Bob Halley's avatar
add adb  
Bob Halley committed
475
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
476 477
				     timermgr, options, dispatchmgr,
				     dispatchv4, dispatchv6,
478
				     &view->resolver);
479 480
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
481
		return (result);
482 483 484 485 486
	}
	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
487 488
	result = dns_adb_create(view->mctx, view, timermgr, taskmgr,
				&view->adb);
489 490 491 492 493 494 495
	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
496

Mark Andrews's avatar
Mark Andrews committed
497
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
David Lawrence's avatar
David Lawrence committed
498 499 500 501 502
				      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
503 504 505 506 507 508 509 510 511
	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;

512
	return (ISC_R_SUCCESS);
513 514 515
}

void
516
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
517
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
518
	REQUIRE(!view->frozen);
519

520
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
521
		dns_db_detach(&view->cachedb);
522 523 524 525 526
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
527 528
}

Bob Halley's avatar
Bob Halley committed
529 530 531 532 533 534 535 536 537 538
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
539 540 541 542
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
543
	if (view->statickeys != NULL)
544
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
545 546 547
	view->statickeys = ring;
}

548 549 550 551 552 553
void
dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
	REQUIRE(DNS_VIEW_VALID(view));
	view->dstport = dstport;
}

554
isc_result_t
555
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
556 557
	isc_result_t result;

558
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
559 560
	REQUIRE(!view->frozen);

561
	result = dns_zt_mount(view->zonetable, zone);
562

Bob Halley's avatar
Bob Halley committed
563
	return (result);
564 565 566 567
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
568 569 570
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

571 572
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
573
		dns_resolver_freeze(view->resolver);
574
	}
Bob Halley's avatar
Bob Halley committed
575 576 577
	view->frozen = ISC_TRUE;
}

578
isc_result_t
579
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
580 581 582 583
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
584
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
585
	if (result == DNS_R_PARTIALMATCH) {
586
		dns_zone_detach(zonep);
587
		result = ISC_R_NOTFOUND;
588
	}
589

590 591 592
	return (result);
}

Bob Halley's avatar
Bob Halley committed
593 594
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
595 596
	      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
597 598 599
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
600 601
	dns_db_t *db, *zdb;
	dns_dbnode_t *node, *znode;
602
	isc_boolean_t is_cache;
Bob Halley's avatar
Bob Halley committed
603
	dns_rdataset_t zrdataset, zsigrdataset;
604
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
605 606 607 608 609 610

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

611
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
612
	REQUIRE(view->frozen);
613 614
	REQUIRE(type != dns_rdatatype_sig);
	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
Bob Halley's avatar
Bob Halley committed
615 616 617 618 619 620

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);
621 622
	zdb = NULL;
	znode = NULL;
Bob Halley's avatar
Bob Halley committed
623 624 625 626

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

642
	is_cache = dns_db_iscache(db);
643

Bob Halley's avatar
Bob Halley committed
644 645 646 647 648
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
649
			     now, &node, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
650 651

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

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

 cleanup:
751 752 753 754
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
755
		if (dns_rdataset_isassociated(rdataset))
756
			dns_rdataset_disassociate(rdataset);
757 758
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
759 760
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
761

762
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
763
		dns_rdataset_disassociate(&zrdataset);
764
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
765 766
			dns_rdataset_disassociate(&zsigrdataset);
	}
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786

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

787 788
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
789 790

	return (result);
791
}
792

793 794 795 796 797 798 799 800 801 802 803
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,
804
			       NULL, NULL, dns_fixedname_name(&foundname),
805
			       rdataset, sigrdataset);
806 807 808 809 810 811 812
	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.
		 */
813
		if (dns_rdataset_isassociated(rdataset))
814
			dns_rdataset_disassociate(rdataset);
815 816
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
817 818 819 820 821 822 823
			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 &&
824
		   result != DNS_R_HINTNXRRSET &&
825
		   result != ISC_R_NOTFOUND) {
826
		if (dns_rdataset_isassociated(rdataset))
827
			dns_rdataset_disassociate(rdataset);
828 829
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
830
			dns_rdataset_disassociate(sigrdataset);
831
		result = ISC_R_NOTFOUND;
832 833 834 835 836
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
837 838 839 840 841 842 843 844
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;
845
	isc_boolean_t is_cache, use_zone, try_hints;
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
	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
870
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
871
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
		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;
	}
897
	is_cache = dns_db_iscache(db);
Bob Halley's avatar
Bob Halley committed
898 899 900 901 902

 db_find:
	/*
	 * Look for the zonecut.
	 */
903
	if (!is_cache) {
Bob Halley's avatar
Bob Halley committed
904 905 906 907 908 909 910 911 912 913 914
		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);
915
			result = dns_name_copy(fname, zfname, NULL);