view.c 23.5 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>
21
#include <isc/string.h>		/* Required for HP/UX (and others?) */
Michael Graff's avatar
Michael Graff committed
22
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
23

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

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

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

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

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

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

145
	result = dns_peerlist_new(view->mctx, &view->peers);
146
	if (result != ISC_R_SUCCESS)
147
		goto cleanup_dynkeys;
Michael Graff's avatar
Michael Graff committed
148
	ISC_LINK_INIT(view, link);
149 150 151 152 153 154
	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
155 156 157
	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
158 159 160 161 162 163
	view->magic = DNS_VIEW_MAGIC;
	
	*viewp = view;

	return (ISC_R_SUCCESS);

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

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

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

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

Bob Halley's avatar
add  
Bob Halley committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192
 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
193 194 195 196 197

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

Bob Halley's avatar
add  
Bob Halley committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	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));
215 216 217
	REQUIRE(view->references == 0);
	REQUIRE(RESSHUTDOWN(view));
	REQUIRE(ADBSHUTDOWN(view));
Mark Andrews's avatar
Mark Andrews committed
218
	REQUIRE(REQSHUTDOWN(view));
Bob Halley's avatar
add  
Bob Halley committed
219

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

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

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

	return (ISC_FALSE);
}

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

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

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

	LOCK(&view->lock);

	INSIST(view->references > 0);
	view->references--;
284 285 286 287 288
	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
289 290
		if (!REQSHUTDOWN(view))
			dns_requestmgr_shutdown(view->requestmgr);
291 292
		done = all_done(view);
	}
Bob Halley's avatar
add  
Bob Halley committed
293 294 295 296
	UNLOCK(&view->lock);

	*viewp = NULL;

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

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

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

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

Mark Andrews's avatar
Mark Andrews committed
349 350 351 352 353 354 355 356 357
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);

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

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

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

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

Bob Halley's avatar
add adb  
Bob Halley committed
399
	result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
400 401
				     timermgr, options, dispatchmgr,
				     dispatchv4, dispatchv6,
402
				     &view->resolver);
403 404
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&view->task);
Bob Halley's avatar
add adb  
Bob Halley committed
405
		return (result);
406 407 408 409 410
	}
	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
411 412
	result = dns_adb_create(view->mctx, view, timermgr, taskmgr,
				&view->adb);
413 414 415 416 417 418 419
	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
420

Mark Andrews's avatar
Mark Andrews committed
421
	result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
422
				       dns_resolver_dispatchmgr(view->resolver),
Mark Andrews's avatar
Mark Andrews committed
423 424 425 426 427 428 429 430 431 432 433 434
				       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;

435
	return (ISC_R_SUCCESS);
436 437 438
}

void
439
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
Bob Halley's avatar
Bob Halley committed
440 441

	/*
442
	 * Set the view's cache.
Bob Halley's avatar
Bob Halley committed
443 444
	 */

445
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
446
	REQUIRE(!view->frozen);
447

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

Bob Halley's avatar
Bob Halley committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
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
472 473 474
void
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
	/*
475
	 * Set the view's static TSIG keyring.
Brian Wellington's avatar
Brian Wellington committed
476 477 478
	 */
	REQUIRE(DNS_VIEW_VALID(view));
	REQUIRE(ring != NULL);
479
	if (view->statickeys != NULL)
480
		dns_tsigkeyring_destroy(&view->statickeys);
Brian Wellington's avatar
Brian Wellington committed
481 482 483
	view->statickeys = ring;
}

484
isc_result_t
485
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
Bob Halley's avatar
Bob Halley committed
486 487 488
	isc_result_t result;

	/*
489
	 * Add zone 'zone' to 'view'.
Bob Halley's avatar
Bob Halley committed
490 491
	 */

492
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
493 494
	REQUIRE(!view->frozen);

495
	result = dns_zt_mount(view->zonetable, zone);
496
	dns_zone_setview(zone, view);
497

Bob Halley's avatar
Bob Halley committed
498
	return (result);
499 500 501 502
}

void
dns_view_freeze(dns_view_t *view) {
Bob Halley's avatar
Bob Halley committed
503 504 505 506 507 508 509 510
	
	/*
	 * Freeze view.
	 */

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

511 512
	if (view->resolver != NULL) {
		INSIST(view->cachedb != NULL);
Bob Halley's avatar
Bob Halley committed
513
		dns_resolver_freeze(view->resolver);
514
	}
Bob Halley's avatar
Bob Halley committed
515 516 517
	view->frozen = ISC_TRUE;
}

518
isc_result_t
519
dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
520 521 522 523
	isc_result_t result;

	REQUIRE(DNS_VIEW_VALID(view));

Bob Halley's avatar
Bob Halley committed
524
	result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
525
	if (result == DNS_R_PARTIALMATCH) {
526
		dns_zone_detach(zonep);
527
		result = ISC_R_NOTFOUND;
528
	}
529

530 531 532
	return (result);
}

Bob Halley's avatar
Bob Halley committed
533 534
isc_result_t
dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
535 536
	      isc_stdtime_t now, unsigned int options,
	      isc_boolean_t use_hints, dns_name_t *foundname,
Bob Halley's avatar
Bob Halley committed
537 538 539 540 541 542
	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	isc_result_t result;
	dns_db_t *db;
	isc_boolean_t is_zone;
	dns_rdataset_t zrdataset, zsigrdataset;
543
	dns_zone_t *zone;
Bob Halley's avatar
Bob Halley committed
544 545 546 547 548 549

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

550
	REQUIRE(DNS_VIEW_VALID(view));
Bob Halley's avatar
Bob Halley committed
551 552 553 554 555 556 557 558 559 560 561 562
	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.
	 */
563
	zone = NULL;
Bob Halley's avatar
Bob Halley committed
564
	db = NULL;
Bob Halley's avatar
Bob Halley committed
565
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
566 567
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
		result = dns_zone_getdb(zone, &db);
568
		if (result != ISC_R_SUCCESS && view->cachedb != NULL)
569
			dns_db_attach(view->cachedb, &db);
570
		else if (result != ISC_R_SUCCESS)
571 572
			goto cleanup;
	} else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
Bob Halley's avatar
Bob Halley committed
573
		dns_db_attach(view->cachedb, &db);
574
	else
Bob Halley's avatar
Bob Halley committed
575 576 577
		goto cleanup;

	is_zone = dns_db_iszone(db);
578

Bob Halley's avatar
Bob Halley committed
579 580 581 582 583
 db_find:
	/*
	 * Now look for an answer in the database.
	 */
	result = dns_db_find(db, name, NULL, type, options,
584
			     now, NULL, foundname, rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
585 586

	if (result == DNS_R_DELEGATION ||
587
	    result == ISC_R_NOTFOUND) {
588
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
589
			dns_rdataset_disassociate(rdataset);
590 591
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
			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;
				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.
			 */
609
			if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
610
				dns_rdataset_clone(&zrdataset, rdataset);
Bob Halley's avatar
Bob Halley committed
611
				if (sigrdataset != NULL &&
612
				    dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
613 614 615 616 617 618 619 620 621
					dns_rdataset_clone(&zsigrdataset,
							   sigrdataset);
				result = DNS_R_GLUE;
				goto cleanup;
			}
		}
		/*
		 * We don't know the answer.
		 */
622
		result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
623 624 625 626 627 628 629 630 631
	} 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;
			dns_rdataset_clone(rdataset, &zrdataset);
			dns_rdataset_disassociate(rdataset);
Bob Halley's avatar
Bob Halley committed
632
			if (sigrdataset != NULL &&
633
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
634 635 636 637 638 639 640 641 642 643 644
				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
645 646
	}

647
	if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
648
		if (dns_rdataset_isassociated(rdataset))
Bob Halley's avatar
Bob Halley committed
649
			dns_rdataset_disassociate(rdataset);
650 651
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
652 653
			dns_rdataset_disassociate(sigrdataset);
		result = dns_db_find(view->hints, name, NULL, type, options,
654
				     now, NULL, foundname,
Bob Halley's avatar
Bob Halley committed
655
				     rdataset, sigrdataset);
Bob Halley's avatar
Bob Halley committed
656 657 658 659 660 661
		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
662
			result = DNS_R_HINT;
Bob Halley's avatar
Bob Halley committed
663
		} else if (result == DNS_R_NXDOMAIN ||
664 665
			   result == DNS_R_NXRRSET)
			result = ISC_R_NOTFOUND;
Bob Halley's avatar
Bob Halley committed
666
	}
Bob Halley's avatar
Bob Halley committed
667 668

 cleanup:
669 670 671 672
	if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
		/*
		 * We don't care about any DNSSEC proof data in these cases.
		 */
673
		if (dns_rdataset_isassociated(rdataset))
674
			dns_rdataset_disassociate(rdataset);
675 676
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
677 678
			dns_rdataset_disassociate(sigrdataset);
	}
Bob Halley's avatar
Bob Halley committed
679

680
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
681
		dns_rdataset_disassociate(&zrdataset);
682
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
683 684 685 686
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
687 688
	if (zone != NULL)
		dns_zone_detach(&zone);
Bob Halley's avatar
Bob Halley committed
689 690

	return (result);
691
}
692

693 694 695 696 697 698 699 700 701 702 703 704 705
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);
706 707 708 709 710 711 712
	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.
		 */
713
		if (dns_rdataset_isassociated(rdataset))
714
			dns_rdataset_disassociate(rdataset);
715 716
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
717 718 719 720 721 722 723
			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 &&
724
		   result != ISC_R_NOTFOUND) {
725
		if (dns_rdataset_isassociated(rdataset))
726
			dns_rdataset_disassociate(rdataset);
727 728
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(sigrdataset))
729
			dns_rdataset_disassociate(sigrdataset);
730
		result = ISC_R_NOTFOUND;
731 732 733 734 735
	}

	return (result);
}

Bob Halley's avatar
Bob Halley committed
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
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
773
	result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
774
	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
Bob Halley's avatar
Bob Halley committed
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 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
		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 &&
825
			    dns_rdataset_isassociated(sigrdataset)) {
Bob Halley's avatar
Bob Halley committed
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 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
				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) {
869
		if (dns_rdataset_isassociated(rdataset)) {
Bob Halley's avatar
Bob Halley committed
870 871
			dns_rdataset_disassociate(rdataset);
			if (sigrdataset != NULL &&
872
			    dns_rdataset_isassociated(sigrdataset))
Bob Halley's avatar
Bob Halley committed
873 874 875 876 877 878
				dns_rdataset_disassociate(sigrdataset);
		}
		result = dns_name_concatenate(zfname, NULL, fname, NULL);
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		dns_rdataset_clone(&zrdataset, rdataset);
879 880
		if (sigrdataset != NULL &&
		    dns_rdataset_isassociated(&zrdataset))
Bob Halley's avatar
Bob Halley committed
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
			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:
899
	if (dns_rdataset_isassociated(&zrdataset)) {
Bob Halley's avatar
Bob Halley committed
900
		dns_rdataset_disassociate(&zrdataset);
901
		if (dns_rdataset_isassociated(&zsigrdataset))
Bob Halley's avatar
Bob Halley committed
902 903 904 905 906 907 908 909 910 911
			dns_rdataset_disassociate(&zsigrdataset);
	}
	if (db != NULL)
		dns_db_detach(&db);
	if (zone != NULL)
		dns_zone_detach(&zone);

	return (result);
}

912 913 914 915
isc_result_t
dns_viewlist_find(dns_viewlist_t *list, const char *name,
		  dns_rdataclass_t rdclass, dns_view_t **viewp)
{
916 917 918 919
	dns_view_t *view;

	REQUIRE(list != NULL);

920 921 922
	for (view = ISC_LIST_HEAD(*list);
	     view != NULL;
	     view = ISC_LIST_NEXT(view, link)) {
923 924 925
		if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
			break;
	}
926 927 928 929 930 931
	if (view == NULL)
		return (ISC_R_NOTFOUND);

	dns_view_attach(view, viewp);

	return (ISC_R_SUCCESS);
932
}
Mark Andrews's avatar
Mark Andrews committed
933

934 935
isc_result_t
dns_view_load(dns_view_t *view, isc_boolean_t stop) {
Mark Andrews's avatar
Mark Andrews committed
936 937 938

	REQUIRE(DNS_VIEW_VALID(view));

939
	return (dns_zt_load(view->zonetable, stop));
Mark Andrews's avatar
Mark Andrews committed
940
}
Brian Wellington's avatar
Brian Wellington committed
941 942 943 944 945 946 947 948 949 950

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