view.c 27.4 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.95 2001/02/05 19:47:05 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
	result = isc_rwlock_init(&view->conflock, 1, 1);
83 84 85 86 87 88 89
	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;
	}
90 91
	view->zonetable = NULL;
	result = dns_zt_create(mctx, rdclass, &view->zonetable);
Bob Halley's avatar
add  
Bob Halley committed
92 93
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
94
				 "dns_zt_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
95 96
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
97
		goto cleanup_rwlock;
Bob Halley's avatar
add  
Bob Halley committed
98
	}
Bob Halley's avatar
Bob Halley committed
99
	view->secroots = NULL;
100
	result = dns_keytable_create(mctx, &view->secroots);
Bob Halley's avatar
Bob Halley committed
101 102
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
103
				 "dns_keytable_create() failed: %s",
Bob Halley's avatar
Bob Halley committed
104 105
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
106
		goto cleanup_zt;
Bob Halley's avatar
Bob Halley committed
107
	}
108 109 110 111 112 113 114 115 116
	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;
	}
117 118 119 120 121 122 123 124 125
	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;
	}
126

127
	view->cache = NULL;
Bob Halley's avatar
Bob Halley committed
128
	view->cachedb = NULL;
Bob Halley's avatar
Bob Halley committed
129
	view->hints = NULL;
Bob Halley's avatar
add  
Bob Halley committed
130
	view->resolver = NULL;
Bob Halley's avatar
add adb  
Bob Halley committed
131
	view->adb = 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;
137
	isc_refcount_init(&view->references, 1);
138
	view->weakrefs = 0;
Mark Andrews's avatar
Mark Andrews committed
139 140
	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
			    DNS_VIEWATTR_REQSHUTDOWN);
Brian Wellington's avatar
Brian Wellington committed
141 142
	view->statickeys = NULL;
	view->dynamickeys = NULL;
143
	view->matchclients = NULL;
144
	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
145
	if (result != ISC_R_SUCCESS)
146
		goto cleanup_fwdtable;
147
	view->peers = NULL;
148

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

167
	result = dns_peerlist_new(view->mctx, &view->peers);
168
	if (result != ISC_R_SUCCESS)
169
		goto cleanup_dynkeys;
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
 cleanup_dynkeys:
187
	dns_tsigkeyring_destroy(&view->dynamickeys);
188

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

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

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

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

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

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

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

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

	return (ISC_FALSE);
}

280 281 282 283 284 285
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

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

286
	isc_refcount_increment(&source->references, NULL);
287 288 289 290

	*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
	unsigned int refs;
295
	isc_boolean_t done = ISC_FALSE;
Bob Halley's avatar
add  
Bob Halley committed
296 297 298 299 300

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

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

	*viewp = NULL;

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

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

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

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

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

392
	UNUSED(task);
393

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

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

416
	UNUSED(task);
417

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

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

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

440
	UNUSED(task);
441

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

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

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

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

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

514
	return (ISC_R_SUCCESS);
515 516 517
}

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

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

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

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

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

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

563
	result = dns_zt_mount(view->zonetable, zone);
564

Bob Halley's avatar
Bob Halley committed
565
	return (result);
566 567 568 569
}

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

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

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

	REQUIRE(DNS_VIEW_VALID(view));

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

592 593 594
	return (result);
}

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

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

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

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

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

644
	is_cache = dns_db_iscache(db);
645

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

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

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

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

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

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

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

	return (result);
793
}
794

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

	return (result);
}

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

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