view.c 27.1 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
 */

Bob Halley's avatar
Bob Halley committed
18
/* $Id: view.c,v 1.97 2001/03/14 21:53:27 halley Exp $ */
David Lawrence's avatar
David Lawrence committed
19

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

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

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

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

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

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

	/*
	 * Create a view.
	 */

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

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

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

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

160
	result = dns_peerlist_new(view->mctx, &view->peers);
161
	if (result != ISC_R_SUCCESS)
162
		goto cleanup_dynkeys;
Michael Graff's avatar
Michael Graff committed
163
	ISC_LINK_INIT(view, link);
164 165 166 167 168 169
	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
170 171 172
	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
173
	view->magic = DNS_VIEW_MAGIC;
174

Bob Halley's avatar
add  
Bob Halley committed
175 176 177 178
	*viewp = view;

	return (ISC_R_SUCCESS);

179
 cleanup_dynkeys:
180
	dns_tsigkeyring_destroy(&view->dynamickeys);
181

182 183 184
 cleanup_fwdtable:
	dns_fwdtable_destroy(&view->fwdtable);

185 186 187
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

188
 cleanup_secroots:
189
	dns_keytable_detach(&view->secroots);
190

191 192
 cleanup_zt:
	dns_zt_detach(&view->zonetable);
Bob Halley's avatar
Bob Halley committed
193

Bob Halley's avatar
add  
Bob Halley committed
194
 cleanup_mutex:
195
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
196 197 198 199 200 201 202 203 204 205 206 207 208

 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));
209
	REQUIRE(isc_refcount_current(&view->references) == 0);
210
	REQUIRE(view->weakrefs == 0);
211 212
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
213
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
214

215 216
	if (view->peers != NULL)
		dns_peerlist_detach(&view->peers);
217
	if (view->dynamickeys != NULL)
218
		dns_tsigkeyring_destroy(&view->dynamickeys);
219
	if (view->statickeys != NULL)
220
		dns_tsigkeyring_destroy(&view->statickeys);
Bob Halley's avatar
add adb  
Bob Halley committed
221 222
	if (view->adb != NULL)
		dns_adb_detach(&view->adb);
Bob Halley's avatar
add  
Bob Halley committed
223 224
	if (view->resolver != NULL)
		dns_resolver_detach(&view->resolver);
Mark Andrews's avatar
Mark Andrews committed
225 226
	if (view->requestmgr != NULL)
		dns_requestmgr_detach(&view->requestmgr);
227 228
	if (view->task != NULL)
		isc_task_detach(&view->task);
Bob Halley's avatar
Bob Halley committed
229 230
	if (view->hints != NULL)
		dns_db_detach(&view->hints);
Bob Halley's avatar
Bob Halley committed
231 232
	if (view->cachedb != NULL)
		dns_db_detach(&view->cachedb);
233 234
	if (view->cache != NULL)
		dns_cache_detach(&view->cache);
235 236
	if (view->matchclients != NULL)
		dns_acl_detach(&view->matchclients);
237 238 239 240
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
241 242
	if (view->v6synthesisacl != NULL)
		dns_acl_detach(&view->v6synthesisacl);
243 244
	if (view->sortlist != NULL)
		dns_acl_detach(&view->sortlist);
245 246
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
247
	dns_fwdtable_destroy(&view->fwdtable);
248
	DESTROYLOCK(&view->lock);
249
	isc_refcount_destroy(&view->references);
Bob Halley's avatar
add  
Bob Halley committed
250 251 252 253
	isc_mem_free(view->mctx, view->name);
	isc_mem_put(view->mctx, view, sizeof *view);
}

254 255 256 257
/*
 * Return true iff 'view' may be freed.
 * The caller must be holding the view lock.
 */
258 259 260
static isc_boolean_t
all_done(dns_view_t *view) {

261 262
	if (isc_refcount_current(&view->references) == 0 &&
	    view->weakrefs == 0 &&
263
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
264 265 266 267 268
		return (ISC_TRUE);

	return (ISC_FALSE);
}

269 270 271 272 273 274
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

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

275
	isc_refcount_increment(&source->references, NULL);
276 277 278 279

	*targetp = source;
}

280 281
static void
view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
Bob Halley's avatar
add  
Bob Halley committed
282
	dns_view_t *view;
283
	unsigned int refs;
284
	isc_boolean_t done = ISC_FALSE;
Bob Halley's avatar
add  
Bob Halley committed
285 286 287 288 289

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

290 291 292
	isc_refcount_decrement(&view->references, &refs);
	if (refs == 0) {
		LOCK(&view->lock);
293 294 295 296
		if (!RESSHUTDOWN(view))
			dns_resolver_shutdown(view->resolver);
		if (!ADBSHUTDOWN(view))
			dns_adb_shutdown(view->adb);
Mark Andrews's avatar
Mark Andrews committed
297 298
		if (!REQSHUTDOWN(view))
			dns_requestmgr_shutdown(view->requestmgr);
299 300 301 302
		if (flush)
			dns_zt_flushanddetach(&view->zonetable);
		else
			dns_zt_detach(&view->zonetable);
303
		done = all_done(view);
304
		UNLOCK(&view->lock);
305
	}
Bob Halley's avatar
add  
Bob Halley committed
306 307 308

	*viewp = NULL;

309 310 311 312
	if (done)
		destroy(view);
}

313
void
314 315 316 317 318 319 320 321 322
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
323
static isc_result_t
324 325
dialup(dns_zone_t *zone, void *dummy) {
	UNUSED(dummy);
Mark Andrews's avatar
Mark Andrews committed
326 327 328 329 330 331 332 333 334 335
	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);
}

336
void
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
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);
}

372 373
static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
374
	dns_view_t *view = event->ev_arg;
375
	isc_boolean_t done;
376

377
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
378 379 380
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

381
	UNUSED(task);
382

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	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) {
398
	dns_view_t *view = event->ev_arg;
399
	isc_boolean_t done;
400

401
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
402 403 404
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

405
	UNUSED(task);
406

407 408 409 410 411 412 413 414 415 416
	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
417 418
		destroy(view);
}
419

Mark Andrews's avatar
Mark Andrews committed
420 421 422 423
static void
req_shutdown(isc_task_t *task, isc_event_t *event) {
	dns_view_t *view = event->ev_arg;
	isc_boolean_t done;
424

Mark Andrews's avatar
Mark Andrews committed
425 426 427 428
	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

429
	UNUSED(task);
430

Mark Andrews's avatar
Mark Andrews committed
431 432 433 434 435 436 437 438 439 440 441 442 443
	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
444
isc_result_t
Bob Halley's avatar
Bob Halley committed
445 446 447 448
dns_view_createresolver(dns_view_t *view,
			isc_taskmgr_t *taskmgr, unsigned int ntasks,
			isc_socketmgr_t *socketmgr,
			isc_timermgr_t *timermgr,
449
			unsigned int options,
450
			dns_dispatchmgr_t *dispatchmgr,
451 452
			dns_dispatch_t *dispatchv4,
			dns_dispatch_t *dispatchv6)
Bob Halley's avatar
Bob Halley committed
453
{
Bob Halley's avatar
add adb  
Bob Halley committed
454
	isc_result_t result;
455
	isc_event_t *event;
Bob Halley's avatar
add adb  
Bob Halley committed
456

457
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
458
	REQUIRE(!view->frozen);
459
	REQUIRE(view->resolver == NULL);
460

Bob Halley's avatar
Bob Halley committed
461
	result = isc_task_create(taskmgr, 0, &view->task);
462 463
	if (result != ISC_R_SUCCESS)
		return (result);
Bob Halley's avatar
Bob Halley committed
464
	isc_task_setname(view->task, "view", view);
465

Bob Halley's avatar
add adb  
Bob Halley committed
466
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
467 468
				     timermgr, options, dispatchmgr,
				     dispatchv4, dispatchv6,
469
				     &view->resolver);
470 471
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
472
		return (result);
473 474 475 476 477
	}
	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
478 479
	result = dns_adb_create(view->mctx, view, timermgr, taskmgr,
				&view->adb);
480 481 482 483 484 485 486
	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
487

Mark Andrews's avatar
Mark Andrews committed
488
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
David Lawrence's avatar
David Lawrence committed
489 490 491 492 493
				      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
494 495 496 497 498 499 500 501 502
	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;

503
	return (ISC_R_SUCCESS);
504 505 506
}

void
507
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
508
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
509
	REQUIRE(!view->frozen);
510

511
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
512
		dns_db_detach(&view->cachedb);
513 514 515 516 517
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
518 519
}

Bob Halley's avatar
Bob Halley committed
520 521 522 523 524 525 526 527 528 529
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
530 531 532 533
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
534
	if (view->statickeys != NULL)
535
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
536 537 538
	view->statickeys = ring;
}

539 540 541 542 543 544
void
dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
	REQUIRE(DNS_VIEW_VALID(view));
	view->dstport = dstport;
}

545
isc_result_t
546
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
547 548
	isc_result_t result;

549
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
550 551
	REQUIRE(!view->frozen);

552
	result = dns_zt_mount(view->zonetable, zone);
553

Bob Halley's avatar
Bob Halley committed
554
	return (result);
555 556 557 558
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
559 560 561
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

562 563
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
564
		dns_resolver_freeze(view->resolver);
565
	}
Bob Halley's avatar
Bob Halley committed
566 567 568
	view->frozen = ISC_TRUE;
}

569
isc_result_t
570
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
571 572 573 574
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
575
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
576
	if (result == DNS_R_PARTIALMATCH) {
577
		dns_zone_detach(zonep);
578
		result = ISC_R_NOTFOUND;
579
	}
580

581 582 583
	return (result);
}

Bob Halley's avatar
Bob Halley committed
584 585
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
586 587
	      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
588 589 590
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
591 592
	dns_db_t *db, *zdb;
	dns_dbnode_t *node, *znode;
593
	isc_boolean_t is_cache;
Bob Halley's avatar
Bob Halley committed
594
	dns_rdataset_t zrdataset, zsigrdataset;
595
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
596 597 598 599 600 601

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

602
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
603
	REQUIRE(view->frozen);
604 605
	REQUIRE(type != dns_rdatatype_sig);
	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
Bob Halley's avatar
Bob Halley committed
606 607 608 609 610 611

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);
612 613
	zdb = NULL;
	znode = NULL;
Bob Halley's avatar
Bob Halley committed
614 615 616 617

	/*
	 * Find a database to answer the query.
	 */
618
	zone = NULL;
Bob Halley's avatar
Bob Halley committed
619
	db = NULL;
620
	node = NULL;
Bob Halley's avatar
Bob Halley committed
621
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
622 623
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
		result = dns_zone_getdb(zone, &db);
624
		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
625
			dns_db_attach(view->cachedb, &db);
626
		else if (result != ISC_R_SUCCESS)
627 628
			goto cleanup;
	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
Bob Halley's avatar
Bob Halley committed
629
		dns_db_attach(view->cachedb, &db);
630
	else
Bob Halley's avatar
Bob Halley committed
631 632
		goto cleanup;

633
	is_cache = dns_db_iscache(db);
634

Bob Halley's avatar
Bob Halley committed
635 636 637 638 639
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
640
			     now, &node, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
641 642

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

712
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
713
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
714
			dns_rdataset_disassociate(rdataset);
715 716
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
717
			dns_rdataset_disassociate(sigrdataset);
718 719 720 721 722
		if (db != NULL) {
			if (node != NULL)
				dns_db_detachnode(db, &node);
			dns_db_detach(&db);
		}
Bob Halley's avatar
Bob Halley committed
723
		result = dns_db_find(view->hints, name, NULL, type, options,
724
				     now, &node, foundname,
Bob Halley's avatar
Bob Halley committed
725
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
726 727 728 729 730 731
		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);
732
			dns_db_attach(view->hints, &db);
Bob Halley's avatar
Bob Halley committed
733
			result = DNS_R_HINT;
734 735 736 737
		} else if (result == DNS_R_NXRRSET) {
			dns_db_attach(view->hints, &db);
			result = DNS_R_HINTNXRRSET;
		} else if (result == DNS_R_NXDOMAIN)
738
			result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
739
	}
Bob Halley's avatar
Bob Halley committed
740 741

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

753
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
754
		dns_rdataset_disassociate(&zrdataset);
755
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
756 757
			dns_rdataset_disassociate(&zsigrdataset);
	}
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777

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

778 779
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
780 781

	return (result);
782
}
783

784 785 786 787 788 789 790 791 792 793 794
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,
795
			       NULL, NULL, dns_fixedname_name(&foundname),
796
			       rdataset, sigrdataset);
797 798 799 800 801 802 803
	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.
		 */
804
		if (dns_rdataset_isassociated(rdataset))
805
			dns_rdataset_disassociate(rdataset);
806 807
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
808 809 810 811 812 813 814
			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 &&
815
		   result != DNS_R_HINTNXRRSET &&
816
		   result != ISC_R_NOTFOUND) {
817
		if (dns_rdataset_isassociated(rdataset))
818
			dns_rdataset_disassociate(rdataset);
819 820
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
821
			dns_rdataset_disassociate(sigrdataset);
822
		result = ISC_R_NOTFOUND;
823 824 825 826 827
	}

	return (result);
}

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

 db_find:
	/*
	 * Look for the zonecut.
	 */
894
	if (!is_cache) {
Bob Halley's avatar
Bob Halley committed
895 896 897 898 899 900 901 902 903 904 905
		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);
906
			result = dns_name_copy(fname, zfname, NULL);
Bob Halley's avatar
Bob Halley committed
907 908 909 910 911
			if (result != ISC_R_SUCCESS)
				goto cleanup;
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
912
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
913 914 915 916 917
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			dns_db_detach(&db);
			dns_db_attach