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.124 2004/02/17 03:40:23 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;
158
	view->enablednssec = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
159
	view->minimalresponses = ISC_FALSE;
160
	view->transfer_format = dns_one_answer;
161 162
	view->queryacl = NULL;
	view->recursionacl = NULL;
163
	view->sortlist = NULL;
164 165
	view->requestixfr = ISC_TRUE;
	view->provideixfr = ISC_TRUE;
166 167
	view->maxcachettl = 7 * 24 * 3600;
	view->maxncachettl = 3 * 3600;
168
	view->dstport = 53;
169
	view->preferred_glue = 0;
170
	view->flush = ISC_FALSE;
171

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

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

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

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

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

	return (ISC_R_SUCCESS);

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

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

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

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

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

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

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

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

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

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

	return (result);
}

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

242 243
	if (view->order != NULL)
		dns_order_detach(&view->order);
244 245
	if (view->peers != NULL)
		dns_peerlist_detach(&view->peers);
246
	if (view->dynamickeys != NULL)
247
		dns_tsigkeyring_destroy(&view->dynamickeys);
248
	if (view->statickeys != NULL)
249
		dns_tsigkeyring_destroy(&view->statickeys);
Bob Halley's avatar
add adb  
Bob Halley committed
250 251
	if (view->adb != NULL)
		dns_adb_detach(&view->adb);
Bob Halley's avatar
add  
Bob Halley committed
252 253
	if (view->resolver != NULL)
		dns_resolver_detach(&view->resolver);
Mark Andrews's avatar
Mark Andrews committed
254 255
	if (view->requestmgr != NULL)
		dns_requestmgr_detach(&view->requestmgr);
256 257
	if (view->task != NULL)
		isc_task_detach(&view->task);
Bob Halley's avatar
Bob Halley committed
258 259
	if (view->hints != NULL)
		dns_db_detach(&view->hints);
Bob Halley's avatar
Bob Halley committed
260 261
	if (view->cachedb != NULL)
		dns_db_detach(&view->cachedb);
262 263
	if (view->cache != NULL)
		dns_cache_detach(&view->cache);
264 265
	if (view->matchclients != NULL)
		dns_acl_detach(&view->matchclients);
266 267
	if (view->matchdestinations != NULL)
		dns_acl_detach(&view->matchdestinations);
268 269 270 271
	if (view->queryacl != NULL)
		dns_acl_detach(&view->queryacl);
	if (view->recursionacl != NULL)
		dns_acl_detach(&view->recursionacl);
272 273
	if (view->sortlist != NULL)
		dns_acl_detach(&view->sortlist);
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
	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
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	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;
	}
309 310
	dns_keytable_detach(&view->trustedkeys);
	dns_keytable_detach(&view->secroots);
311
	dns_fwdtable_destroy(&view->fwdtable);
312
	dns_aclenv_destroy(&view->aclenv);
313
	DESTROYLOCK(&view->lock);
314
	isc_refcount_destroy(&view->references);
Bob Halley's avatar
add  
Bob Halley committed
315
	isc_mem_free(view->mctx, view->name);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
316
	isc_mem_put(view->mctx, view, sizeof(*view));
Bob Halley's avatar
add  
Bob Halley committed
317 318
}

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

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

	return (ISC_FALSE);
}

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

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

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

	*targetp = source;
}

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

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

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

	*viewp = NULL;

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

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

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

403
void
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 438
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);
}

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

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

448
	UNUSED(task);
449

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

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

472
	UNUSED(task);
473

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

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

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

496
	UNUSED(task);
497

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

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

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

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

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

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

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

577
	return (ISC_R_SUCCESS);
578 579 580
}

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

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

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

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

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

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

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

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

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

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

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

	REQUIRE(DNS_VIEW_VALID(view));

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

655 656 657
	return (result);
}

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

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

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

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

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

707
	is_cache = dns_db_iscache(db);
708

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

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

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

		/*
		 * 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
819
	}
Bob Halley's avatar
Bob Halley committed
820 821

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

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

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

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

	return (result);
863
}
864

865 866 867 868 869 870 871 872 873 874 875
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,