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

18
/* $Id: view.c,v 1.84 2000/11/03 18:27:31 gson Exp $ */
David Lawrence's avatar
David Lawrence committed
19

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

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

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

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

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

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

	/*
	 * Create a view.
	 */

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

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

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

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

165
	result = dns_peerlist_new(view->mctx, &view->peers);
166
	if (result != ISC_R_SUCCESS)
167
		goto cleanup_dynkeys;
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
 cleanup_dynkeys:
185
	dns_tsigkeyring_destroy(&view->dynamickeys);
186

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

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

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

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

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

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(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);
233 234
	if (view->loadmgr != NULL)
		dns_loadmgr_detach(&view->loadmgr);
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 249 250
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
251 252
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
253
	dns_fwdtable_destroy(&view->fwdtable);
254
	isc_rwlock_destroy(&view->conflock);
255
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
256 257 258 259
	isc_mem_free(view->mctx, view->name);
	isc_mem_put(view->mctx, view, sizeof *view);
}

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

267 268
	if (view->references == 0 && view->weakrefs == 0 &&
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
269 270 271 272 273
		return (ISC_TRUE);

	return (ISC_FALSE);
}

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

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

	LOCK(&source->lock);

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

	UNLOCK(&source->lock);

	*targetp = source;
}

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

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

	LOCK(&view->lock);

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

	*viewp = NULL;

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

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

348
void
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 381 382 383
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);
}

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

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

393
	UNUSED(task);
394

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

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

417
	UNUSED(task);
418

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

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

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

441
	UNUSED(task);
442

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

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

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

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

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

515
	return (ISC_R_SUCCESS);
516 517 518
}

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

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

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

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

557 558 559 560 561 562 563 564 565
void
dns_view_setloadmgr(dns_view_t *view, dns_loadmgr_t *loadmgr) {
	REQUIRE(DNS_VIEW_VALID(view));

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

566
isc_result_t
567
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
568 569
	isc_result_t result;

570
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
571 572
	REQUIRE(!view->frozen);

573
	result = dns_zt_mount(view->zonetable, zone);
574

Bob Halley's avatar
Bob Halley committed
575
	return (result);
576 577 578 579
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
580 581 582
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

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

590
isc_result_t
591
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
592 593 594 595
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

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

602 603 604
	return (result);
}

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

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

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

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

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

649
	is_cache = dns_db_iscache(db);
650

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

	if (result == DNS_R_DELEGATION ||
659
	    result == ISC_R_NOTFOUND) {
660
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
661
			dns_rdataset_disassociate(rdataset);
662 663
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
664
			dns_rdataset_disassociate(sigrdataset);
665
		if (!is_cache) {
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 680
				dns_db_detach(&db);
				dns_db_attach(view->cachedb, &db);
				goto db_find;
			}
		} else {
			/*
			 * We don't have the data in the cache.  If we've got
			 * glue from the zone, use it.
			 */
681
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
682
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
683
				if (sigrdataset != NULL &&
684
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
685 686 687 688 689 690 691 692 693
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
694
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
695 696 697 698 699 700
	} 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.
			 */
701
			is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
702 703
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
704
			if (sigrdataset != NULL &&
705
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
706 707 708 709 710 711 712 713 714 715 716
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			dns_db_detach(&db);
			dns_db_attach(view->cachedb, &db);
			goto db_find;
		}
		/*
		 * Otherwise, the glue is the best answer.
		 */
		result = ISC_R_SUCCESS;
Bob Halley's avatar
Bob Halley committed
717 718
	}

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

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

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

	return (result);
763
}
764

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

	dns_fixedname_init(&foundname);
	result = dns_view_find(view, name, type, now, options, use_hints,
			       dns_fixedname_name(&foundname),
			       rdataset, sigrdataset);
778 779 780 781 782 783 784
	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.
		 */
785
		if (dns_rdataset_isassociated(rdataset))
786
			dns_rdataset_disassociate(rdataset);
787 788
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
789 790 791 792 793 794 795
			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 &&
796
		   result != ISC_R_NOTFOUND) {
797
		if (dns_rdataset_isassociated(rdataset))
798
			dns_rdataset_disassociate(rdataset);
799 800
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
801
			dns_rdataset_disassociate(sigrdataset);
802
		result = ISC_R_NOTFOUND;
803 804 805 806 807
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
808 809 810 811 812 813 814 815
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;
816
	isc_boolean_t is_cache, use_zone, try_hints;
Bob Halley's avatar
Bob Halley committed
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
	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
841
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
842
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
		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;
	}
868
	is_cache = dns_db_iscache(db);
Bob Halley's avatar
Bob Halley committed
869 870 871 872 873

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

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

 cleanup:
967
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
968
		dns_rdataset_disassociate(&zrdataset);
969
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
970 971 972 973 974 975 976 977 978 979
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
	if (zone != NULL)
		dns_zone_detach(&zone);

	return (result);
}