view.c 33.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.121 2003/09/19 13:27:18 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
	isc_mem_create(0, 0, &mctx);
	result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
	isc_mem_detach(&mctx);
548 549 550 551 552 553 554
	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
555

Mark Andrews's avatar
Mark Andrews committed
556
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
David Lawrence's avatar
David Lawrence committed
557 558 559 560 561
				      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
562 563 564 565 566 567 568 569 570
	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;

571
	return (ISC_R_SUCCESS);
572 573 574
}

void
575
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
576
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
577
	REQUIRE(!view->frozen);
578

579
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
580
		dns_db_detach(&view->cachedb);
581 582 583 584 585
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
586 587
}

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

607 608 609 610 611 612
void
dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
	REQUIRE(DNS_VIEW_VALID(view));
	view->dstport = dstport;
}

613
isc_result_t
614
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
615 616
	isc_result_t result;

617
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
618 619
	REQUIRE(!view->frozen);

620
	result = dns_zt_mount(view->zonetable, zone);
621

Bob Halley's avatar
Bob Halley committed
622
	return (result);
623 624 625 626
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
627 628 629
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

630 631
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
632
		dns_resolver_freeze(view->resolver);
633
	}
Bob Halley's avatar
Bob Halley committed
634 635 636
	view->frozen = ISC_TRUE;
}

637
isc_result_t
638
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
639 640 641 642
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
643
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
644
	if (result == DNS_R_PARTIALMATCH) {
645
		dns_zone_detach(zonep);
646
		result = ISC_R_NOTFOUND;
647
	}
648

649 650 651
	return (result);
}

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

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

670
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
671
	REQUIRE(view->frozen);
672 673
	REQUIRE(type != dns_rdatatype_sig);
	REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
Bob Halley's avatar
Bob Halley committed
674 675 676 677 678 679

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);
680 681
	zdb = NULL;
	znode = NULL;
Bob Halley's avatar
Bob Halley committed
682 683 684 685

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

701
	is_cache = dns_db_iscache(db);
702

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

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

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

		/*
		 * 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
813
	}
Bob Halley's avatar
Bob Halley committed
814 815

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

827
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
828
		dns_rdataset_disassociate(&zrdataset);
829
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
830 831
			dns_rdataset_disassociate(&zsigrdataset);
	}
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849

	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);
850 851
	} else
		INSIST(node == NULL);
852

853 854
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
855 856

	return (result);
857
}
858

859 860 861 862 863 864 865 866 867 868 869
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,
870
			       NULL, NULL, dns_fixedname_name(&foundname),
871
			       rdataset, sigrdataset);
872 873 874 875 876 877 878
	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 mis