view.c 28 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.101 2001/07/26 20:42:44 bwelling 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 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);
171 172 173 174 175 176
	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
177 178 179
	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
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 211 212 213 214 215 216 217 218

 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));
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 264 265 266
	isc_mem_free(view->mctx, view->name);
	isc_mem_put(view->mctx, view, sizeof *view);
}

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;
Bob Halley's avatar
add adb  
Bob Halley committed
469

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

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

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

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

516
	return (ISC_R_SUCCESS);
517 518 519
}

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

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

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

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

558
isc_result_t
559
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
560 561
	isc_result_t result;

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

565
	result = dns_zt_mount(view->zonetable, zone);
566

Bob Halley's avatar
Bob Halley committed
567
	return (result);
568 569 570 571
}

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

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

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

	REQUIRE(DNS_VIEW_VALID(view));

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

594 595 596
	return (result);
}

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

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

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

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

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

646
	is_cache = dns_db_iscache(db);
647

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

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

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

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

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

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

791 792
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
793 794

	return (result);
795
}
796

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

	return (result);
}

Bob Halley's avatar
Bob Halley committed
841 842 843 844 845 846 847 848
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;
849
	isc_boolean_t is_cache, use_zone, try_hints;
Bob Halley's avatar
Bob Halley committed
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
	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
874
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
875
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
		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;
	}
901
	is_cache = dns_db_iscache(db);
Bob Halley's avatar
Bob Halley committed
902 903 904 905 906

 db_find:
	/*
	 * Look for the zonecut.
	 */
907
	if (!is_cache) {
Bob Halley's avatar
Bob Halley committed
908 909 910 911 912 913 914 915 916 917 918
		result = dns_db_find(db, name, NULL, dns_rdatatype_ns,