view.c 24 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
Bob Halley's avatar
add  
Bob Halley committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 
 * 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.
 * 
 * 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.
 */

#include <config.h>

20
#include <isc/task.h>
Michael Graff's avatar
Michael Graff committed
21
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
22

23
#include <dns/acl.h>
Bob Halley's avatar
add adb  
Bob Halley committed
24
#include <dns/adb.h>
25
#include <dns/cache.h>
Bob Halley's avatar
Bob Halley committed
26
#include <dns/db.h>
27
#include <dns/events.h>
28
#include <dns/keytable.h>
29
#include <dns/peer.h>
Bob Halley's avatar
Bob Halley committed
30
#include <dns/rdataset.h>
Mark Andrews's avatar
Mark Andrews committed
31
#include <dns/request.h>
32 33
#include <dns/resolver.h>
#include <dns/result.h>
Brian Wellington's avatar
Brian Wellington committed
34
#include <dns/tsig.h>
35
#include <dns/zone.h>
36
#include <dns/zt.h>
Bob Halley's avatar
add  
Bob Halley committed
37

38 39
#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
40
#define REQSHUTDOWN(v)	(((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
41 42 43

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
44
static void req_shutdown(isc_task_t *task, isc_event_t *event);
45

Bob Halley's avatar
add  
Bob Halley committed
46
isc_result_t
47 48
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
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
{
	dns_view_t *view;
	isc_result_t result;

	/*
	 * Create a view.
	 */

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

	view = isc_mem_get(mctx, sizeof *view);
	if (view == NULL)
		return (ISC_R_NOMEMORY);
	view->name = isc_mem_strdup(mctx, name);
	if (view->name == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup_view;
	}
	result = isc_mutex_init(&view->lock);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_mutex_init() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_name;
	}
76
	result = isc_rwlock_init(&view->conflock, 1, 1);
77 78 79 80 81 82 83
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_rwlock_init() failed: %s",
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
		goto cleanup_mutex;
	}
84 85
	view->zonetable = NULL;
	result = dns_zt_create(mctx, rdclass, &view->zonetable);
Bob Halley's avatar
add  
Bob Halley committed
86 87
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
88
				 "dns_zt_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
89 90
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
91
		goto cleanup_rwlock;
Bob Halley's avatar
add  
Bob Halley committed
92
	}
Bob Halley's avatar
Bob Halley committed
93
	view->secroots = NULL;
94
	result = dns_keytable_create(mctx, &view->secroots);
Bob Halley's avatar
Bob Halley committed
95 96
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
97
				 "dns_keytable_create() failed: %s",
Bob Halley's avatar
Bob Halley committed
98 99
				 isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
100
		goto cleanup_zt;
Bob Halley's avatar
Bob Halley committed
101
	}
102 103 104 105 106 107 108 109 110
	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;
	}
111

112
	view->cache = NULL;
Bob Halley's avatar
Bob Halley committed
113
	view->cachedb = NULL;
Bob Halley's avatar
Bob Halley committed
114
	view->hints = NULL;
Bob Halley's avatar
add  
Bob Halley committed
115
	view->resolver = NULL;
Bob Halley's avatar
add adb  
Bob Halley committed
116
	view->adb = NULL;
Mark Andrews's avatar
Mark Andrews committed
117
	view->requestmgr = NULL;
Bob Halley's avatar
add  
Bob Halley committed
118 119
	view->mctx = mctx;
	view->rdclass = rdclass;
Bob Halley's avatar
Bob Halley committed
120
	view->frozen = ISC_FALSE;
121
	view->task = NULL;
Bob Halley's avatar
add  
Bob Halley committed
122
	view->references = 1;
Mark Andrews's avatar
Mark Andrews committed
123 124
	view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
			    DNS_VIEWATTR_REQSHUTDOWN);
Brian Wellington's avatar
Brian Wellington committed
125 126
	view->statickeys = NULL;
	view->dynamickeys = NULL;
127
	view->matchclients = NULL;
128
	result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
129
	if (result != ISC_R_SUCCESS)
130
		goto cleanup_trustedkeys;
131
	view->peers = NULL;
132

133 134 135
	/*
	 * Initialize configuration data with default values.
	 */	
136 137 138
	view->recursion = ISC_TRUE;
	view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
	view->transfer_format = dns_one_answer;
139 140
	view->queryacl = NULL;
	view->recursionacl = NULL;
141 142
	view->requestixfr = ISC_TRUE;
	view->provideixfr = ISC_TRUE;
143

144
	result = dns_peerlist_new(view->mctx, &view->peers);
145
	if (result != ISC_R_SUCCESS)
146
		goto cleanup_dynkeys;
Michael Graff's avatar
Michael Graff committed
147
	ISC_LINK_INIT(view, link);
148 149 150 151 152 153
	ISC_EVENT_INIT(&view->resevent, sizeof view->resevent, 0, NULL,
		       DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
		       view, NULL, NULL, NULL);
	ISC_EVENT_INIT(&view->adbevent, sizeof view->adbevent, 0, NULL,
		       DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
		       view, NULL, NULL, NULL);
Mark Andrews's avatar
Mark Andrews committed
154 155 156
	ISC_EVENT_INIT(&view->reqevent, sizeof view->reqevent, 0, NULL,
		       DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
		       view, NULL, NULL, NULL);
Bob Halley's avatar
add  
Bob Halley committed
157 158 159 160 161 162
	view->magic = DNS_VIEW_MAGIC;
	
	*viewp = view;

	return (ISC_R_SUCCESS);

163 164 165
 cleanup_dynkeys:
	dns_tsigkeyring_destroy(&view->dynamickeys);	

166 167 168
 cleanup_trustedkeys:
	dns_keytable_detach(&view->trustedkeys);

169
 cleanup_secroots:
170
	dns_keytable_detach(&view->secroots);
171
	
172 173
 cleanup_zt:
	dns_zt_detach(&view->zonetable);
Bob Halley's avatar
Bob Halley committed
174

175 176 177
 cleanup_rwlock:
	isc_rwlock_destroy(&view->conflock);

Bob Halley's avatar
add  
Bob Halley committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191
 cleanup_mutex:
	isc_mutex_destroy(&view->lock);

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

 cleanup_view:
	isc_mem_put(mctx, view, sizeof *view);

	return (result);
}

void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
Bob Halley's avatar
Bob Halley committed
192 193 194 195 196

	/*
	 * Attach '*targetp' to 'source'.
	 */

Bob Halley's avatar
add  
Bob Halley committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	REQUIRE(DNS_VIEW_VALID(source));
	REQUIRE(targetp != NULL && *targetp == NULL);

	LOCK(&source->lock);

	INSIST(source->references > 0);
	source->references++;
	INSIST(source->references != 0);

	UNLOCK(&source->lock);

	*targetp = source;
}

static inline void
destroy(dns_view_t *view) {
	REQUIRE(!ISC_LINK_LINKED(view, link));
214 215 216
	REQUIRE(view->references == 0);
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
217
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
218

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

253 254 255 256 257 258
static isc_boolean_t
all_done(dns_view_t *view) {
	/*
	 * Caller must be holding the view lock.
	 */

Mark Andrews's avatar
Mark Andrews committed
259 260
	if (view->references == 0 && RESSHUTDOWN(view) &&
	    ADBSHUTDOWN(view) && REQSHUTDOWN(view))
261 262 263 264 265
		return (ISC_TRUE);

	return (ISC_FALSE);
}

Bob Halley's avatar
add  
Bob Halley committed
266 267 268
void
dns_view_detach(dns_view_t **viewp) {
	dns_view_t *view;
269
	isc_boolean_t done = ISC_FALSE;
Bob Halley's avatar
add  
Bob Halley committed
270

Bob Halley's avatar
Bob Halley committed
271 272 273 274
	/*
	 * Detach '*viewp' from its view.
	 */

Bob Halley's avatar
add  
Bob Halley committed
275 276 277 278 279 280 281 282
	REQUIRE(viewp != NULL);
	view = *viewp;
	REQUIRE(DNS_VIEW_VALID(view));

	LOCK(&view->lock);

	INSIST(view->references > 0);
	view->references--;
283 284 285 286 287
	if (view->references == 0) {
		if (!RESSHUTDOWN(view))
			dns_resolver_shutdown(view->resolver);
		if (!ADBSHUTDOWN(view))
			dns_adb_shutdown(view->adb);
Mark Andrews's avatar
Mark Andrews committed
288 289
		if (!REQSHUTDOWN(view))
			dns_requestmgr_shutdown(view->requestmgr);
290 291
		done = all_done(view);
	}
Bob Halley's avatar
add  
Bob Halley committed
292 293 294 295
	UNLOCK(&view->lock);

	*viewp = NULL;

296 297 298 299 300 301
	if (done)
		destroy(view);
}

static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
302
	dns_view_t *view = event->ev_arg;
303 304
	isc_boolean_t done;
	
305
	REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
306 307 308
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

309 310
	UNUSED(task);
	
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
	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) {
326
	dns_view_t *view = event->ev_arg;
327 328
	isc_boolean_t done;
	
329
	REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
330 331 332
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

333 334
	UNUSED(task);
	
335 336 337 338 339 340 341 342 343 344
	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
345 346
		destroy(view);
}
347

Mark Andrews's avatar
Mark Andrews committed
348 349 350 351 352 353 354 355 356
static void
req_shutdown(isc_task_t *task, isc_event_t *event) {
	dns_view_t *view = event->ev_arg;
	isc_boolean_t done;
	
	REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->task == task);

357 358
	UNUSED(task);
	
Mark Andrews's avatar
Mark Andrews committed
359 360 361 362 363 364 365 366 367 368 369 370 371
	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
372
isc_result_t
Bob Halley's avatar
Bob Halley committed
373 374 375 376
dns_view_createresolver(dns_view_t *view,
			isc_taskmgr_t *taskmgr, unsigned int ntasks,
			isc_socketmgr_t *socketmgr,
			isc_timermgr_t *timermgr,
377 378 379
			unsigned int options,
			dns_dispatch_t *dispatchv4,
			dns_dispatch_t *dispatchv6)
Bob Halley's avatar
Bob Halley committed
380
{
Bob Halley's avatar
add adb  
Bob Halley committed
381
	isc_result_t result;
382
	isc_event_t *event;
Bob Halley's avatar
add adb  
Bob Halley committed
383

Bob Halley's avatar
Bob Halley committed
384
	/*
Bob Halley's avatar
add adb  
Bob Halley committed
385
	 * Create a resolver and address database for the view.
Bob Halley's avatar
Bob Halley committed
386 387
	 */

388
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
389
	REQUIRE(!view->frozen);
390
	REQUIRE(view->resolver == NULL);
391

Bob Halley's avatar
Bob Halley committed
392
	result = isc_task_create(taskmgr, 0, &view->task);
393 394
	if (result != ISC_R_SUCCESS)
		return (result);
Bob Halley's avatar
Bob Halley committed
395
	isc_task_setname(view->task, "view", view);
396

Bob Halley's avatar
add adb  
Bob Halley committed
397
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
398 399
				     timermgr, options, dispatchv4, dispatchv6,
				     &view->resolver);
400 401
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
402
		return (result);
403 404 405 406 407
	}
	event = &view->resevent;
	dns_resolver_whenshutdown(view->resolver, view->task, &event);
	view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;

Bob Halley's avatar
add adb  
Bob Halley committed
408 409
	result = dns_adb_create(view->mctx, view, timermgr, taskmgr,
				&view->adb);
410 411 412 413 414 415 416
	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
417

Mark Andrews's avatar
Mark Andrews committed
418 419 420 421 422 423 424 425 426 427 428 429 430
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
				       dns_resolver_dispatchv4(view->resolver),
				       dns_resolver_dispatchv6(view->resolver),
				       &view->requestmgr);
	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;

431
	return (ISC_R_SUCCESS);
432 433 434
}

void
435
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
Bob Halley's avatar
Bob Halley committed
436 437

	/*
438
	 * Set the view's cache.
Bob Halley's avatar
Bob Halley committed
439 440
	 */

441
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
442
	REQUIRE(!view->frozen);
443

444
	if (view->cache != NULL) {
Bob Halley's avatar
add adb  
Bob Halley committed
445
		dns_db_detach(&view->cachedb);
446 447 448 449 450
		dns_cache_detach(&view->cache);
	}
	dns_cache_attach(cache, &view->cache);
	dns_cache_attachdb(cache, &view->cachedb);
	INSIST(DNS_DB_VALID(view->cachedb));
451 452
}

Bob Halley's avatar
Bob Halley committed
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
void
dns_view_sethints(dns_view_t *view, dns_db_t *hints) {

	/*
	 * Set the view's hints database.
	 */

	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
468 469 470
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	/*
471
	 * Set the view's static TSIG keyring.
Brian Wellington's avatar
Brian Wellington committed
472 473 474
	 */
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
475
	if (view->statickeys != NULL)
476
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
477 478 479
	view->statickeys = ring;
}

480
isc_result_t
481
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
482 483 484
	isc_result_t result;

	/*
485
	 * Add zone 'zone' to 'view'.
Bob Halley's avatar
Bob Halley committed
486 487
	 */

488
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
489 490
	REQUIRE(!view->frozen);

491
	result = dns_zt_mount(view->zonetable, zone);
492
	dns_zone_setview(zone, view);
493

Bob Halley's avatar
Bob Halley committed
494
	return (result);
495 496
}

Mark Andrews's avatar
Mark Andrews committed
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
static isc_result_t
set_resolver(dns_zone_t *zone, void *ptr) {
	dns_zone_setresolver(zone, ptr);
	return (ISC_R_SUCCESS);
}

static isc_result_t
set_requestmgr(dns_zone_t *zone, void *ptr) {
	dns_zone_setrequestmgr(zone, ptr);
	return (ISC_R_SUCCESS);
}

static isc_result_t
set_adb(dns_zone_t *zone, void *ptr) {
	dns_zone_setadb(zone, ptr);
	return (ISC_R_SUCCESS);
}

515 516
void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
517 518 519 520 521 522 523 524
	
	/*
	 * Freeze view.
	 */

	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(!view->frozen);

525 526
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
527
		dns_resolver_freeze(view->resolver);
Mark Andrews's avatar
Mark Andrews committed
528 529 530 531 532 533 534 535 536 537
		(void)dns_zt_apply(view->zonetable, ISC_FALSE,
				   set_resolver, view->resolver);
	}
	if (view->requestmgr != NULL) {
		(void)dns_zt_apply(view->zonetable, ISC_FALSE,
				   set_requestmgr, view->requestmgr);
	}
	if (view->adb != NULL) {
		(void)dns_zt_apply(view->zonetable, ISC_FALSE,
				   set_adb, view->adb);
538
	}
Bob Halley's avatar
Bob Halley committed
539 540 541
	view->frozen = ISC_TRUE;
}

542
isc_result_t
543
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
544 545 546 547
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
548
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
549
	if (result == DNS_R_PARTIALMATCH) {
550
		dns_zone_detach(zonep);
551
		result = ISC_R_NOTFOUND;
552
	}
553

554 555 556
	return (result);
}

Bob Halley's avatar
Bob Halley committed
557 558
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
559 560
	      isc_stdtime_t now, unsigned int options,
	      isc_boolean_t use_hints, dns_name_t *foundname,
Bob Halley's avatar
Bob Halley committed
561 562 563 564 565 566 567
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_db_t *db;
	dns_dbversion_t *version;
	isc_boolean_t is_zone;
	dns_rdataset_t zrdataset, zsigrdataset;
568
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
569 570 571 572 573 574

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

575
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
576 577 578 579 580 581 582 583 584 585 586 587
	REQUIRE(view->frozen);
	REQUIRE(type != dns_rdatatype_any && type != dns_rdatatype_sig);

	/*
	 * Initialize.
	 */
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);

	/*
	 * Find a database to answer the query.
	 */
588
	zone = NULL;
Bob Halley's avatar
Bob Halley committed
589
	db = NULL;
Bob Halley's avatar
Bob Halley committed
590
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
591 592
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
		result = dns_zone_getdb(zone, &db);
593
		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
594
			dns_db_attach(view->cachedb, &db);
595
		else if (result != ISC_R_SUCCESS)
596 597
			goto cleanup;
	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
Bob Halley's avatar
Bob Halley committed
598
		dns_db_attach(view->cachedb, &db);
599
	else
Bob Halley's avatar
Bob Halley committed
600 601 602
		goto cleanup;

	is_zone = dns_db_iszone(db);
603

Bob Halley's avatar
Bob Halley committed
604 605 606 607 608
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
609
			     now, NULL, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
610 611

	if (result == DNS_R_DELEGATION ||
612
	    result == ISC_R_NOTFOUND) {
613
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
614
			dns_rdataset_disassociate(rdataset);
615 616
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
			dns_rdataset_disassociate(sigrdataset);
		if (is_zone) {
			if (view->cachedb != NULL) {
				/*
				 * Either the answer is in the cache, or we
				 * don't know it.
				 */
				is_zone = ISC_FALSE;
				version = NULL;
				dns_db_detach(&db);
				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.
			 */
635
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
636
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
637
				if (sigrdataset != NULL &&
638
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
639 640 641 642 643 644 645 646 647
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
648
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
649 650 651 652 653 654 655 656 657 658
	} 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.
			 */
			is_zone = ISC_FALSE;
			version = NULL;
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
659
			if (sigrdataset != NULL &&
660
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
661 662 663 664 665 666 667 668 669 670 671
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			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
672 673
	}

674
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
675
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
676
			dns_rdataset_disassociate(rdataset);
677 678
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
679 680
			dns_rdataset_disassociate(sigrdataset);
		result = dns_db_find(view->hints, name, NULL, type, options,
681
				     now, NULL, foundname,
Bob Halley's avatar
Bob Halley committed
682
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
683 684 685 686 687 688
		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);
Bob Halley's avatar
Bob Halley committed
689
			result = DNS_R_HINT;
Bob Halley's avatar
Bob Halley committed
690
		} else if (result == DNS_R_NXDOMAIN ||
691 692
			   result == DNS_R_NXRRSET)
			result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
693
	}
Bob Halley's avatar
Bob Halley committed
694 695

 cleanup:
696 697 698 699
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
700
		if (dns_rdataset_isassociated(rdataset))
701
			dns_rdataset_disassociate(rdataset);
702 703
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
704 705
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
706

707
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
708
		dns_rdataset_disassociate(&zrdataset);
709
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
710 711 712 713
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
714 715
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
716 717

	return (result);
718
}
719

720 721 722 723 724 725 726 727 728 729 730 731 732
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,
			       dns_fixedname_name(&foundname),
			       rdataset, sigrdataset);
733 734 735 736 737 738 739
	if (result == DNS_R_NXDOMAIN) {
		/*
		 * The rdataset and sigrdataset of the relevant NXT record
		 * may be returned, but the caller cannot use them because
		 * foundname is not returned by this simplified API.  We
		 * disassociate them here to prevent any misuse by the caller.
		 */
740
		if (dns_rdataset_isassociated(rdataset))
741
			dns_rdataset_disassociate(rdataset);
742 743
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
744 745 746 747 748 749 750
			dns_rdataset_disassociate(sigrdataset);
	} else if (result != ISC_R_SUCCESS &&
		   result != DNS_R_GLUE &&
		   result != DNS_R_HINT &&
		   result != DNS_R_NCACHENXDOMAIN &&
		   result != DNS_R_NCACHENXRRSET &&
		   result != DNS_R_NXRRSET &&
751
		   result != ISC_R_NOTFOUND) {
752
		if (dns_rdataset_isassociated(rdataset))
753
			dns_rdataset_disassociate(rdataset);
754 755
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
756
			dns_rdataset_disassociate(sigrdataset);
757
		result = ISC_R_NOTFOUND;
758 759 760 761 762
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
isc_result_t
dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
		     isc_stdtime_t now, unsigned int options,
		     isc_boolean_t use_hints,
		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_db_t *db;
	isc_boolean_t is_zone, use_zone, try_hints;
	dns_zone_t *zone;
	dns_name_t *zfname;
	dns_rdataset_t zrdataset, zsigrdataset;
	dns_fixedname_t zfixedname;

	/*
	 * Find the best known zonecut containing 'name'.
	 */

	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(view->frozen);

	db = NULL;
	zone = NULL;
	use_zone = ISC_FALSE;
	try_hints = ISC_FALSE;
	zfname = NULL;

	/*
	 * Initialize.
	 */
	dns_fixedname_init(&zfixedname);
	dns_rdataset_init(&zrdataset);
	dns_rdataset_init(&zsigrdataset);

	/*
	 * Find the right database.
	 */
Bob Halley's avatar
Bob Halley committed
800
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
801
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
		result = dns_zone_getdb(zone, &db);
	if (result == ISC_R_NOTFOUND) {
		/*
		 * We're not directly authoritative for this query name, nor
		 * is it a subdomain of any zone for which we're
		 * authoritative.
		 */
		if (view->cachedb != NULL) {
			/*
			 * We have a cache; try it.
			 */
			dns_db_attach(view->cachedb, &db);
		} else {
			/*
			 * Maybe we have hints...
			 */
			try_hints = ISC_TRUE;
			goto finish;
		}
	} else if (result != ISC_R_SUCCESS) {
		/*
		 * Something is broken.
		 */
		goto cleanup;
	}
	is_zone = dns_db_iszone(db);

 db_find:
	/*
	 * Look for the zonecut.
	 */
	if (is_zone) {
		result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
				     now, NULL, fname, rdataset, sigrdataset);
		if (result == DNS_R_DELEGATION)
			result = ISC_R_SUCCESS;
		else if (result != ISC_R_SUCCESS)
			goto cleanup;
		if (view->cachedb != NULL && db != view->hints) {
			/*
			 * We found an answer, but the cache may be better.
			 */
			zfname = dns_fixedname_name(&zfixedname);
			result = dns_name_concatenate(fname, NULL, zfname,
						      NULL);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
852
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
				dns_rdataset_clone(sigrdataset, &zsigrdataset);
				dns_rdataset_disassociate(sigrdataset);
			}
			dns_db_detach(&db);
			dns_db_attach(view->cachedb, &db);
			is_zone = ISC_FALSE;
			goto db_find;
		}
	} else {
		result = dns_db_findzonecut(db, name, options, now, NULL,
					    fname, rdataset, sigrdataset);
		if (result == ISC_R_SUCCESS) {
			if (zfname != NULL &&
			    !dns_name_issubdomain(fname, zfname)) {
				/*
				 * We found a zonecut in the cache, but our
				 * zone delegation is better.
				 */
				use_zone = ISC_TRUE;
			}
		} else if (result == ISC_R_NOTFOUND) {
			if (zfname != NULL) {
				/*
				 * We didn't find anything in the cache, but we
				 * have a zone delegation, so use it.
				 */
				use_zone = ISC_TRUE;
			} else {
				/*
				 * Maybe we have hints...
				 */
				try_hints = ISC_TRUE;
			}
		} else {
			/*
			 * Something bad happened.
			 */
			goto cleanup;
		}
	}

 finish:
	if (use_zone) {
896
		if (dns_rdataset_isassociated(rdataset)) {
Bob Halley's avatar
Bob Halley committed
897 898
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
899
			    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
900 901 902 903 904 905
				dns_rdataset_disassociate(sigrdataset);
		}
		result = dns_name_concatenate(zfname, NULL, fname, NULL);
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		dns_rdataset_clone(&zrdataset, rdataset);
906 907
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(&zrdataset))
Bob Halley's avatar
Bob Halley committed
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
			dns_rdataset_clone(&zsigrdataset, sigrdataset);
	} else if (try_hints && use_hints && view->hints != NULL) {
		/*
		 * We've found nothing so far, but we have hints.
		 */
		result = dns_db_find(view->hints, dns_rootname, NULL,
				     dns_rdatatype_ns, 0, now, NULL, fname,
				     rdataset, NULL);
		if (result != ISC_R_SUCCESS) {
			/*
			 * We can't even find the hints for the root
			 * nameservers!
			 */
			result = ISC_R_NOTFOUND;
		}
	}

 cleanup:
926
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
927
		dns_rdataset_disassociate(&zrdataset);
928
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
929 930 931 932 933 934 935 936 937 938
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
	if (zone != NULL)
		dns_zone_detach(&zone);

	return (result);
}

939 940 941 942
isc_result_t
dns_viewlist_find(dns_viewlist_t *list, const char *name,
		  dns_rdataclass_t rdclass, dns_view_t **viewp)
{
943 944 945 946
	dns_view_t *view;

	REQUIRE(list != NULL);

947 948 949
	for (view = ISC_LIST_HEAD(*list);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link)) {
950 951 952
		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
			break;
	}
953 954 955 956 957 958
	if (view == NULL)
		return (ISC_R_NOTFOUND);

	dns_view_attach(view, viewp);

	return (ISC_R_SUCCESS);
959
}
Mark Andrews's avatar
Mark Andrews committed
960

961 962
isc_result_t
dns_view_load(dns_view_t *view, isc_boolean_t stop) {
Mark Andrews's avatar
Mark Andrews committed
963 964 965

	REQUIRE(DNS_VIEW_VALID(view));

966
	return (dns_zt_load(view->zonetable, stop));
Mark Andrews's avatar
Mark Andrews committed
967
}
Brian Wellington's avatar
Brian Wellington committed
968 969 970 971 972 973 974 975 976 977

isc_result_t
dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(source != NULL);

	return dns_tsig_verify(source, msg, view->statickeys,
			       view->dynamickeys);
}