view.c 33.5 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.123 2003/10/03 02:19:31 marka 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/hash.h>
23
#include <isc/task.h>
24
#include <isc/string.h>		/* Required for HP/UX (and others?) */
Michael Graff's avatar
Michael Graff committed
25
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
26

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

46 47
#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
48
#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
49

50 51
#define DNS_VIEW_DELONLYHASH 111

52 53
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
54
static void req_shutdown(isc_task_t *task, isc_event_t *event);
55

Bob Halley's avatar
add  
Bob Halley committed
56
isc_result_t
57 58
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
59 60 61 62 63 64 65 66 67 68 69
{
	dns_view_t *view;
	isc_result_t result;

	/*
	 * Create a view.
	 */

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

Andreas Gustafsson's avatar
Andreas Gustafsson committed
70
	view = isc_mem_get(mctx, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	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;
	}
86 87
	view->zonetable = NULL;
	result = dns_zt_create(mctx, rdclass, &view->zonetable);
Bob Halley's avatar
add  
Bob Halley committed
88 89
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
90
				 "dns_zt_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
91 92
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
93
		goto cleanup_mutex;
Bob Halley's avatar
add  
Bob Halley committed
94
	}
Bob Halley's avatar
Bob Halley committed
95
	view->secroots = NULL;
96
	result = dns_keytable_create(mctx, &view->secroots);
Bob Halley's avatar
Bob Halley committed
97 98
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
99
				 "dns_keytable_create() failed: %s",
Bob Halley's avatar
Bob Halley committed
100 101
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
102
		goto cleanup_zt;
Bob Halley's avatar
Bob Halley committed
103
	}
104 105 106 107 108 109 110 111 112
	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;
	}
113 114 115 116 117 118 119 120 121
	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;
	}
122

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

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

171
	result = dns_order_create(view->mctx, &view->order);
172
	if (result != ISC_R_SUCCESS)
173
		goto cleanup_dynkeys;
174

175 176 177 178
	result = dns_peerlist_new(view->mctx, &view->peers);
	if (result != ISC_R_SUCCESS)
		goto cleanup_order;

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

Michael Graff's avatar
Michael Graff committed
183
	ISC_LINK_INIT(view, link);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
184
	ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
185 186
		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
		       view, NULL, NULL, NULL);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
187
	ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
188 189
		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
		       view, NULL, NULL, NULL);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
190
	ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
Mark Andrews's avatar
Mark Andrews committed
191 192
		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
		       view, NULL, NULL, NULL);
Bob Halley's avatar
add  
Bob Halley committed
193
	view->magic = DNS_VIEW_MAGIC;
194

Bob Halley's avatar
add  
Bob Halley committed
195 196 197 198
	*viewp = view;

	return (ISC_R_SUCCESS);

199 200 201
 cleanup_peerlist:
	dns_peerlist_detach(&view->peers);

202 203 204
 cleanup_order:
	dns_order_detach(&view->order);

205
 cleanup_dynkeys:
206
	dns_tsigkeyring_destroy(&view->dynamickeys);
207

208 209 210
 cleanup_fwdtable:
	dns_fwdtable_destroy(&view->fwdtable);

211 212 213
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

214
 cleanup_secroots:
215
	dns_keytable_detach(&view->secroots);
216

217 218
 cleanup_zt:
	dns_zt_detach(&view->zonetable);
Bob Halley's avatar
Bob Halley committed
219

Bob Halley's avatar
add  
Bob Halley committed
220
 cleanup_mutex:
221
	DESTROYLOCK(&view->lock);
Bob Halley's avatar
add  
Bob Halley committed
222 223 224 225 226

 cleanup_name:
	isc_mem_free(mctx, view->name);

 cleanup_view:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
227
	isc_mem_put(mctx, view, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
228 229 230 231 232 233 234

	return (result);
}

static inline void
destroy(dns_view_t *view) {
	REQUIRE(!ISC_LINK_LINKED(view, link));
235
	REQUIRE(isc_refcount_current(&view->references) == 0);
236
	REQUIRE(view->weakrefs == 0);
237 238
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
239
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
240

241 242
	if (view->order != NULL)
		dns_order_detach(&view->order);
243 244
	if (view->peers != NULL)
		dns_peerlist_detach(&view->peers);
245
	if (view->dynamickeys != NULL)
246
		dns_tsigkeyring_destroy(&view->dynamickeys);
247
	if (view->statickeys != NULL)
248
		dns_tsigkeyring_destroy(&view->statickeys);
Bob Halley's avatar
add adb  
Bob Halley committed
249 250
	if (view->adb != NULL)
		dns_adb_detach(&view->adb);
Bob Halley's avatar
add  
Bob Halley committed
251 252
	if (view->resolver != NULL)
		dns_resolver_detach(&view->resolver);
Mark Andrews's avatar
Mark Andrews committed
253 254
	if (view->requestmgr != NULL)
		dns_requestmgr_detach(&view->requestmgr);
255 256
	if (view->task != NULL)
		isc_task_detach(&view->task);
Bob Halley's avatar
Bob Halley committed
257 258
	if (view->hints != NULL)
		dns_db_detach(&view->hints);
Bob Halley's avatar
Bob Halley committed
259 260
	if (view->cachedb != NULL)
		dns_db_detach(&view->cachedb);
261 262
	if (view->cache != NULL)
		dns_cache_detach(&view->cache);
263 264
	if (view->matchclients != NULL)
		dns_acl_detach(&view->matchclients);
265 266
	if (view->matchdestinations != NULL)
		dns_acl_detach(&view->matchdestinations);
267 268 269 270
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
271 272
	if (view->sortlist != NULL)
		dns_acl_detach(&view->sortlist);
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	if (view->delonly != NULL) {
		dns_name_t *name;
		int i;

		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
			name = ISC_LIST_HEAD(view->delonly[i]);
			while (name != NULL) {
				ISC_LIST_UNLINK(view->delonly[i], name, link);
				dns_name_free(name, view->mctx);
				isc_mem_put(view->mctx, name, sizeof(*name));
				name = ISC_LIST_HEAD(view->delonly[i]);
			}
		}
		isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
			    DNS_VIEW_DELONLYHASH);
		view->delonly = NULL;
	}
Mark Andrews's avatar
Mark Andrews committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	if (view->rootexclude != NULL) {
		dns_name_t *name;
		int i;

		for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
			name = ISC_LIST_HEAD(view->rootexclude[i]);
			while (name != NULL) {
				ISC_LIST_UNLINK(view->rootexclude[i],
					 	name, link);
				dns_name_free(name, view->mctx);
				isc_mem_put(view->mctx, name, sizeof(*name));
				name = ISC_LIST_HEAD(view->rootexclude[i]);
			}
		}
		isc_mem_put(view->mctx, view->rootexclude,
			    sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
		view->rootexclude = NULL;
	}
308 309
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
310
	dns_fwdtable_destroy(&view->fwdtable);
311
	dns_aclenv_destroy(&view->aclenv);
312
	DESTROYLOCK(&view->lock);
313
	isc_refcount_destroy(&view->references);
Bob Halley's avatar
add  
Bob Halley committed
314
	isc_mem_free(view->mctx, view->name);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
315
	isc_mem_put(view->mctx, view, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
316 317
}

318 319 320 321
/*
 * Return true iff 'view' may be freed.
 * The caller must be holding the view lock.
 */
322 323 324
static isc_boolean_t
all_done(dns_view_t *view) {

325 326
	if (isc_refcount_current(&view->references) == 0 &&
	    view->weakrefs == 0 &&
327
	    RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
328 329 330 331 332
		return (ISC_TRUE);

	return (ISC_FALSE);
}

333 334 335 336 337 338
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {

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

339
	isc_refcount_increment(&source->references, NULL);
340 341 342 343

	*targetp = source;
}

344 345
static void
view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
Bob Halley's avatar
add  
Bob Halley committed
346
	dns_view_t *view;
347
	unsigned int refs;
348
	isc_boolean_t done = ISC_FALSE;
Bob Halley's avatar
add  
Bob Halley committed
349 350 351 352 353

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

354 355
	if (flush)
		view->flush = ISC_TRUE;
356 357 358
	isc_refcount_decrement(&view->references, &refs);
	if (refs == 0) {
		LOCK(&view->lock);
359 360 361 362
		if (!RESSHUTDOWN(view))
			dns_resolver_shutdown(view->resolver);
		if (!ADBSHUTDOWN(view))
			dns_adb_shutdown(view->adb);
Mark Andrews's avatar
Mark Andrews committed
363 364
		if (!REQSHUTDOWN(view))
			dns_requestmgr_shutdown(view->requestmgr);
365
		if (view->flush)
366 367 368
			dns_zt_flushanddetach(&view->zonetable);
		else
			dns_zt_detach(&view->zonetable);
369
		done = all_done(view);
370
		UNLOCK(&view->lock);
371
	}
Bob Halley's avatar
add  
Bob Halley committed
372 373 374

	*viewp = NULL;

375 376 377 378
	if (done)
		destroy(view);
}

379
void
380 381 382 383 384 385 386 387 388
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
389
static isc_result_t
390 391
dialup(dns_zone_t *zone, void *dummy) {
	UNUSED(dummy);
Mark Andrews's avatar
Mark Andrews committed
392 393 394 395 396 397 398
	dns_zone_dialup(zone);
	return (ISC_R_SUCCESS);
}

void
dns_view_dialup(dns_view_t *view) {
	REQUIRE(DNS_VIEW_VALID(view));
399
	(void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
Mark Andrews's avatar
Mark Andrews committed
400 401
}

402
void
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
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);
}

438 439
static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
440
	dns_view_t *view = event->ev_arg;
441
	isc_boolean_t done;
442

443
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
444 445 446
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

447
	UNUSED(task);
448

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
	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) {
464
	dns_view_t *view = event->ev_arg;
465
	isc_boolean_t done;
466

467
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
468 469 470
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

471
	UNUSED(task);
472

473 474 475 476 477 478 479 480 481 482
	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
483 484
		destroy(view);
}
485

Mark Andrews's avatar
Mark Andrews committed
486 487 488 489
static void
req_shutdown(isc_task_t *task, isc_event_t *event) {
	dns_view_t *view = event->ev_arg;
	isc_boolean_t done;
490

Mark Andrews's avatar
Mark Andrews committed
491 492 493 494
	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

495
	UNUSED(task);
496

Mark Andrews's avatar
Mark Andrews committed
497 498 499 500 501 502 503 504 505 506 507 508 509
	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
510
isc_result_t
Bob Halley's avatar
Bob Halley committed
511 512 513 514
dns_view_createresolver(dns_view_t *view,
			isc_taskmgr_t *taskmgr, unsigned int ntasks,
			isc_socketmgr_t *socketmgr,
			isc_timermgr_t *timermgr,
515
			unsigned int options,
516
			dns_dispatchmgr_t *dispatchmgr,
517 518
			dns_dispatch_t *dispatchv4,
			dns_dispatch_t *dispatchv6)
Bob Halley's avatar
Bob Halley committed
519
{
Bob Halley's avatar
add adb  
Bob Halley committed
520
	isc_result_t result;
521
	isc_event_t *event;
522
	isc_mem_t *mctx = NULL;
Bob Halley's avatar
add adb  
Bob Halley committed
523

524
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
525
	REQUIRE(!view->frozen);
526
	REQUIRE(view->resolver == NULL);
527

Bob Halley's avatar
Bob Halley committed
528
	result = isc_task_create(taskmgr, 0, &view->task);
529 530
	if (result != ISC_R_SUCCESS)
		return (result);
Bob Halley's avatar
Bob Halley committed
531
	isc_task_setname(view->task, "view", view);
532

Bob Halley's avatar
add adb  
Bob Halley committed
533
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
534 535
				     timermgr, options, dispatchmgr,
				     dispatchv4, dispatchv6,
536
				     &view->resolver);
537 538
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
539
		return (result);
540 541 542 543 544
	}
	event = &view->resevent;
	dns_resolver_whenshutdown(view->resolver, view->task, &event);
	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;

545 546 547 548 549 550
	result = isc_mem_create(0, 0, &mctx);
	if (result != ISC_R_SUCCESS) {
		dns_resolver_shutdown(view->resolver);
		return (result);
	}

551 552
	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
	isc_mem_detach(&mctx);
553 554 555 556 557 558 559
	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
560

Mark Andrews's avatar
Mark Andrews committed
561
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
David Lawrence's avatar
David Lawrence committed
562 563 564 565 566
				      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
567 568 569 570 571 572 573 574 575
	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;

576
	return (ISC_R_SUCCESS);
577 578 579
}

void
580
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
581
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
582
	REQUIRE(!view->frozen);
583

584
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
585
		dns_db_detach(&view->cachedb);
586 587 588 589 590
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
591 592
}

Bob Halley's avatar
Bob Halley committed
593 594 595 596 597 598 599 600 601 602
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
603 604 605 606
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
607
	if (view->statickeys != NULL)
608
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
609 610 611
	view->statickeys = ring;
}

612 613 614 615 616 617
void
dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
	REQUIRE(DNS_VIEW_VALID(view));
	view->dstport = dstport;
}

618
isc_result_t
619
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
620 621
	isc_result_t result;

622
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
623 624
	REQUIRE(!view->frozen);

625
	result = dns_zt_mount(view->zonetable, zone);
626

Bob Halley's avatar
Bob Halley committed
627
	return (result);
628 629 630 631
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
632 633 634
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

635 636
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
637
		dns_resolver_freeze(view->resolver);
638
	}
Bob Halley's avatar
Bob Halley committed
639 640 641
	view->frozen = ISC_TRUE;
}

642
isc_result_t
643
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
644 645 646 647
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
648
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
649
	if (result == DNS_R_PARTIALMATCH) {
650
		dns_zone_detach(zonep);
651
		result = ISC_R_NOTFOUND;
652
	}
653

654 655 656
	return (result);
}

Bob Halley's avatar
Bob Halley committed
657 658
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
659 660
	      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
661 662 663
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
664 665
	dns_db_t *db, *zdb;
	dns_dbnode_t *node, *znode;
666
	isc_boolean_t is_cache;
Bob Halley's avatar
Bob Halley committed
667
	dns_rdataset_t zrdataset, zsigrdataset;
668
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
669 670 671 672 673 674

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

675
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
676
	REQUIRE(view->frozen);
677
	REQUIRE(type != dns_rdatatype_rrsig);
678
	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
Bob Halley's avatar
Bob Halley committed
679 680 681 682 683 684

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);
685 686
	zdb = NULL;
	znode = NULL;
Bob Halley's avatar
Bob Halley committed
687 688 689 690

	/*
	 * Find a database to answer the query.
	 */
691
	zone = NULL;
Bob Halley's avatar
Bob Halley committed
692
	db = NULL;
693
	node = NULL;
Bob Halley's avatar
Bob Halley committed
694
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
695 696
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
		result = dns_zone_getdb(zone, &db);
697
		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
698
			dns_db_attach(view->cachedb, &db);
699
		else if (result != ISC_R_SUCCESS)
700 701
			goto cleanup;
	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
Bob Halley's avatar
Bob Halley committed
702
		dns_db_attach(view->cachedb, &db);
703
	else
Bob Halley's avatar
Bob Halley committed
704 705
		goto cleanup;

706
	is_cache = dns_db_iscache(db);
707

Bob Halley's avatar
Bob Halley committed
708 709 710 711 712
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
713
			     now, &node, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
714 715

	if (result == DNS_R_DELEGATION ||
716
	    result == ISC_R_NOTFOUND) {
717
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
718
			dns_rdataset_disassociate(rdataset);
719 720
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
721
			dns_rdataset_disassociate(sigrdataset);
722 723
		if (node != NULL)
			dns_db_detachnode(db, &node);
724
		if (!is_cache) {
725
			dns_db_detach(&db);
Bob Halley's avatar
Bob Halley committed
726 727 728 729 730
			if (view->cachedb != NULL) {
				/*
				 * Either the answer is in the cache, or we
				 * don't know it.
				 */
731
				is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
732 733 734 735 736 737 738 739
				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.
			 */
740
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
741
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
742
				if (sigrdataset != NULL &&
743
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
744 745 746
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
747 748 749 750
				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
751 752 753 754 755 756
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
757
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
758 759 760 761 762 763
	} 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.
			 */
764
			is_cache = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
765 766
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
767
			if (sigrdataset != NULL &&
768
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
769 770 771
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
772 773 774
			dns_db_attach(db, &zdb);
			dns_db_attachnode(zdb, node, &znode);
			dns_db_detachnode(db, &node);
Bob Halley's avatar
Bob Halley committed
775 776 777 778 779 780 781 782
			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
783 784
	}

785
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
786
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
787
			dns_rdataset_disassociate(rdataset);
788 789
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
790
			dns_rdataset_disassociate(sigrdataset);
791 792 793 794 795
		if (db != NULL) {
			if (node != NULL)
				dns_db_detachnode(db, &node);
			dns_db_detach(&db);
		}
Bob Halley's avatar
Bob Halley committed
796
		result = dns_db_find(view->hints, name, NULL, type, options,
797
				     now, &node, foundname,
Bob Halley's avatar
Bob Halley committed
798
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
799 800 801 802 803 804
		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);
805
			dns_db_attach(view->hints, &db);
Bob Halley's avatar
Bob Halley committed
806
			result = DNS_R_HINT;
807 808 809 810
		} else if (result == DNS_R_NXRRSET) {
			dns_db_attach(view->hints, &db);
			result = DNS_R_HINTNXRRSET;
		} else if (result == DNS_R_NXDOMAIN)
811
			result = ISC_R_NOTFOUND;
812 813 814 815 816 817

		/*
		 * Cleanup if non-standard hints are used.
		 */
		if (db == NULL && node != NULL)
			dns_db_detachnode(view->hints, &node);
Bob Halley's avatar
Bob Halley committed
818
	}
Bob Halley's avatar
Bob Halley committed
819 820

 cleanup:
821 822 823 824
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
825
		if (dns_rdataset_isassociated(rdataset))
826
			dns_rdataset_disassociate(rdataset);
827 828
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
829 830
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
831

832
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
833
		dns_rdataset_disassociate(&zrdataset);
834
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
835 836
			dns_rdataset_disassociate(&zsigrdataset);
	}
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854

	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);
855 856
	} else
		INSIST(node == NULL);
857

858 859
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
860 861

	return (result);
862
}
863

864 865 866 867 868 869 870 871 872 873 874
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,
875
			       NULL, NULL, dns_fixedname_name(&foundname),