db.c 26.2 KB
Newer Older
Bob Halley's avatar
Bob Halley committed
1
/*
2
 * Copyright (C) 2004, 2005, 2007-2009, 2011-2013, 2015, 2016  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Bob Halley's avatar
Bob Halley committed
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC 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
Bob Halley committed
16 17
 */

18
/*! \file */
David Lawrence's avatar
David Lawrence committed
19

20 21 22 23
/***
 *** Imports
 ***/

Bob Halley's avatar
Bob Halley committed
24 25
#include <config.h>

26
#include <isc/buffer.h>
27 28 29
#include <isc/mem.h>
#include <isc/once.h>
#include <isc/rwlock.h>
30
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
31
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
32

33
#include <dns/callbacks.h>
34
#include <dns/clientinfo.h>
35
#include <dns/db.h>
36
#include <dns/dbiterator.h>
37
#include <dns/log.h>
Bob Halley's avatar
Bob Halley committed
38
#include <dns/master.h>
39
#include <dns/rdata.h>
40
#include <dns/rdataset.h>
41
#include <dns/rdatasetiter.h>
42
#include <dns/result.h>
43 44 45 46 47

/***
 *** Private Types
 ***/

48 49 50 51 52 53 54
struct dns_dbimplementation {
	const char *				name;
	dns_dbcreatefunc_t			create;
	isc_mem_t *				mctx;
	void *					driverarg;
	ISC_LINK(dns_dbimplementation_t)	link;
};
55 56 57 58 59 60

/***
 *** Supported DB Implementations Registry
 ***/

/*
61
 * Built in database implementations are registered here.
62
 */
Bob Halley's avatar
Bob Halley committed
63 64

#include "rbtdb.h"
65
#include "rbtdb64.h"
Bob Halley's avatar
Bob Halley committed
66

67 68 69 70 71 72 73 74
static ISC_LIST(dns_dbimplementation_t) implementations;
static isc_rwlock_t implock;
static isc_once_t once = ISC_ONCE_INIT;

static dns_dbimplementation_t rbtimp;
static dns_dbimplementation_t rbt64imp;

static void
75
initialize(void) {
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	RUNTIME_CHECK(isc_rwlock_init(&implock, 0, 0) == ISC_R_SUCCESS);

	rbtimp.name = "rbt";
	rbtimp.create = dns_rbtdb_create;
	rbtimp.mctx = NULL;
	rbtimp.driverarg = NULL;
	ISC_LINK_INIT(&rbtimp, link);

	rbt64imp.name = "rbt64";
	rbt64imp.create = dns_rbtdb64_create;
	rbt64imp.mctx = NULL;
	rbt64imp.driverarg = NULL;
	ISC_LINK_INIT(&rbt64imp, link);

	ISC_LIST_INIT(implementations);
	ISC_LIST_APPEND(implementations, &rbtimp, link);
	ISC_LIST_APPEND(implementations, &rbt64imp, link);
}

static inline dns_dbimplementation_t *
impfind(const char *name) {
	dns_dbimplementation_t *imp;

Automatic Updater's avatar
Automatic Updater committed
99
	for (imp = ISC_LIST_HEAD(implementations);
100 101 102 103 104 105 106
	     imp != NULL;
	     imp = ISC_LIST_NEXT(imp, link))
		if (strcasecmp(name, imp->name) == 0)
			return (imp);
	return (NULL);
}

107 108 109 110 111

/***
 *** Basic DB Methods
 ***/

112
isc_result_t
David Lawrence's avatar
David Lawrence committed
113
dns_db_create(isc_mem_t *mctx, const char *db_type, dns_name_t *origin,
114
	      dns_dbtype_t type, dns_rdataclass_t rdclass,
Bob Halley's avatar
Bob Halley committed
115 116
	      unsigned int argc, char *argv[], dns_db_t **dbp)
{
117 118 119
	dns_dbimplementation_t *impinfo;

	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
120 121 122 123 124 125 126

	/*
	 * Create a new database using implementation 'db_type'.
	 */

	REQUIRE(dbp != NULL && *dbp == NULL);
	REQUIRE(dns_name_isabsolute(origin));
Bob Halley's avatar
Bob Halley committed
127

128 129 130 131 132 133 134 135 136 137 138 139
	RWLOCK(&implock, isc_rwlocktype_read);
	impinfo = impfind(db_type);
	if (impinfo != NULL) {
		isc_result_t result;
		result = ((impinfo->create)(mctx, origin, type,
					    rdclass, argc, argv,
					    impinfo->driverarg, dbp));
		RWUNLOCK(&implock, isc_rwlocktype_read);
		return (result);
	}

	RWUNLOCK(&implock, isc_rwlocktype_read);
Bob Halley's avatar
Bob Halley committed
140

141 142 143 144
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DB, ISC_LOG_ERROR,
		      "unsupported database type '%s'", db_type);

145
	return (ISC_R_NOTFOUND);
Bob Halley's avatar
Bob Halley committed
146 147 148 149 150
}

void
dns_db_attach(dns_db_t *source, dns_db_t **targetp) {

151 152 153 154
	/*
	 * Attach *targetp to source.
	 */

Bob Halley's avatar
Bob Halley committed
155
	REQUIRE(DNS_DB_VALID(source));
156
	REQUIRE(targetp != NULL && *targetp == NULL);
Bob Halley's avatar
Bob Halley committed
157 158

	(source->methods->attach)(source, targetp);
159 160

	ENSURE(*targetp == source);
Bob Halley's avatar
Bob Halley committed
161 162 163 164 165 166
}

void
dns_db_detach(dns_db_t **dbp) {

	/*
167
	 * Detach *dbp from its database.
Bob Halley's avatar
Bob Halley committed
168 169 170 171 172 173
	 */

	REQUIRE(dbp != NULL);
	REQUIRE(DNS_DB_VALID(*dbp));

	((*dbp)->methods->detach)(dbp);
174 175

	ENSURE(*dbp == NULL);
Bob Halley's avatar
Bob Halley committed
176 177
}

178 179 180 181 182 183 184 185 186
isc_result_t
dns_db_ondestroy(dns_db_t *db, isc_task_t *task, isc_event_t **eventp)
{
	REQUIRE(DNS_DB_VALID(db));

	return (isc_ondestroy_register(&db->ondest, task, eventp));
}


Bob Halley's avatar
Bob Halley committed
187 188
isc_boolean_t
dns_db_iscache(dns_db_t *db) {
189 190 191 192

	/*
	 * Does 'db' have cache semantics?
	 */
193

Bob Halley's avatar
Bob Halley committed
194 195
	REQUIRE(DNS_DB_VALID(db));

196 197 198 199
	if ((db->attributes & DNS_DBATTR_CACHE) != 0)
		return (ISC_TRUE);

	return (ISC_FALSE);
Bob Halley's avatar
Bob Halley committed
200 201 202 203
}

isc_boolean_t
dns_db_iszone(dns_db_t *db) {
204 205 206 207

	/*
	 * Does 'db' have zone semantics?
	 */
208

Bob Halley's avatar
Bob Halley committed
209 210
	REQUIRE(DNS_DB_VALID(db));

211 212 213 214 215 216 217 218 219 220 221 222
	if ((db->attributes & (DNS_DBATTR_CACHE|DNS_DBATTR_STUB)) == 0)
		return (ISC_TRUE);

	return (ISC_FALSE);
}

isc_boolean_t
dns_db_isstub(dns_db_t *db) {

	/*
	 * Does 'db' have stub semantics?
	 */
223

224 225 226
	REQUIRE(DNS_DB_VALID(db));

	if ((db->attributes & DNS_DBATTR_STUB) != 0)
227 228 229
		return (ISC_TRUE);

	return (ISC_FALSE);
Bob Halley's avatar
Bob Halley committed
230 231
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
isc_boolean_t
dns_db_isdnssec(dns_db_t *db) {

	/*
	 * Is 'db' secure or partially secure?
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);

	if (db->methods->isdnssec != NULL)
		return ((db->methods->isdnssec)(db));
	return ((db->methods->issecure)(db));
}

Bob Halley's avatar
Bob Halley committed
247 248 249 250 251 252
isc_boolean_t
dns_db_issecure(dns_db_t *db) {

	/*
	 * Is 'db' secure?
	 */
253

Bob Halley's avatar
Bob Halley committed
254 255 256 257 258 259
	REQUIRE(DNS_DB_VALID(db));
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);

	return ((db->methods->issecure)(db));
}

260 261 262 263 264 265 266 267 268 269 270 271
isc_boolean_t
dns_db_ispersistent(dns_db_t *db) {

	/*
	 * Is 'db' persistent?
	 */

	REQUIRE(DNS_DB_VALID(db));

	return ((db->methods->ispersistent)(db));
}

Bob Halley's avatar
Bob Halley committed
272 273
dns_name_t *
dns_db_origin(dns_db_t *db) {
274 275 276 277
	/*
	 * The origin of the database.
	 */

Bob Halley's avatar
Bob Halley committed
278 279
	REQUIRE(DNS_DB_VALID(db));

280
	return (&db->origin);
Bob Halley's avatar
Bob Halley committed
281 282
}

Bob Halley's avatar
Bob Halley committed
283 284 285 286 287 288 289 290 291 292 293
dns_rdataclass_t
dns_db_class(dns_db_t *db) {
	/*
	 * The class of the database.
	 */

	REQUIRE(DNS_DB_VALID(db));

	return (db->rdclass);
}

294
isc_result_t
295
dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
Bob Halley's avatar
Bob Halley committed
296 297 298 299 300
	/*
	 * Begin loading 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
301
	REQUIRE(DNS_CALLBACK_VALID(callbacks));
Bob Halley's avatar
Bob Halley committed
302

303
	return ((db->methods->beginload)(db, callbacks));
Bob Halley's avatar
Bob Halley committed
304 305
}

306
isc_result_t
307
dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
308 309
	dns_dbonupdatelistener_t *listener;

Bob Halley's avatar
Bob Halley committed
310 311 312 313 314
	/*
	 * Finish loading 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
315 316
	REQUIRE(DNS_CALLBACK_VALID(callbacks));
	REQUIRE(callbacks->add_private != NULL);
Bob Halley's avatar
Bob Halley committed
317

318 319 320 321 322
	for (listener = ISC_LIST_HEAD(db->update_listeners);
	     listener != NULL;
	     listener = ISC_LIST_NEXT(listener, link))
		listener->onupdate(db, listener->onupdate_arg);

323
	return ((db->methods->endload)(db, callbacks));
Bob Halley's avatar
Bob Halley committed
324 325
}

326
isc_result_t
Bob Halley's avatar
Bob Halley committed
327
dns_db_load(dns_db_t *db, const char *filename) {
328
	return (dns_db_load3(db, filename, dns_masterformat_text, 0));
329 330 331 332
}

isc_result_t
dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) {
333 334 335 336 337
	return (dns_db_load3(db, filename, format, 0));
}

isc_result_t
dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format,
338 339
	     unsigned int options)
{
340
	isc_result_t result, eresult;
Bob Halley's avatar
Bob Halley committed
341 342
	dns_rdatacallbacks_t callbacks;

343 344 345
	/*
	 * Load master file 'filename' into 'db'.
	 */
Bob Halley's avatar
Bob Halley committed
346 347 348

	REQUIRE(DNS_DB_VALID(db));

Bob Halley's avatar
Bob Halley committed
349
	if ((db->attributes & DNS_DBATTR_CACHE) != 0)
350
		options |= DNS_MASTER_AGETTL;
Bob Halley's avatar
Bob Halley committed
351 352

	dns_rdatacallbacks_init(&callbacks);
353
	result = dns_db_beginload(db, &callbacks);
354
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
355
		return (result);
356 357 358
	result = dns_master_loadfile2(filename, &db->origin, &db->origin,
				      db->rdclass, options,
				      &callbacks, db->mctx, format);
359
	eresult = dns_db_endload(db, &callbacks);
Bob Halley's avatar
Bob Halley committed
360 361
	/*
	 * We always call dns_db_endload(), but we only want to return its
362
	 * result if dns_master_loadfile() succeeded.  If dns_master_loadfile()
Bob Halley's avatar
Bob Halley committed
363 364
	 * failed, we want to return the result code it gave us.
	 */
365 366
	if (eresult != ISC_R_SUCCESS &&
	    (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
Bob Halley's avatar
Bob Halley committed
367 368 369
		result = eresult;

	return (result);
Bob Halley's avatar
Bob Halley committed
370 371
}

Tinderbox User's avatar
Tinderbox User committed
372
isc_result_t
373 374 375 376 377 378 379
dns_db_serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file) {
	REQUIRE(DNS_DB_VALID(db));
	if (db->methods->serialize == NULL)
		return (ISC_R_NOTIMPLEMENTED);
	return ((db->methods->serialize)(db, version, file));
}

380
isc_result_t
Bob Halley's avatar
Bob Halley committed
381
dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
382 383 384 385 386 387 388
	return ((db->methods->dump)(db, version, filename,
				    dns_masterformat_text));
}

isc_result_t
dns_db_dump2(dns_db_t *db, dns_dbversion_t *version, const char *filename,
	     dns_masterformat_t masterformat) {
389
	/*
390 391 392
	 * Dump 'db' into master file 'filename' in the 'masterformat' format.
	 * XXXJT: is it okay to modify the interface to the existing "dump"
	 * method?
393 394 395 396
	 */

	REQUIRE(DNS_DB_VALID(db));

397
	return ((db->methods->dump)(db, version, filename, masterformat));
398 399
}

400 401 402
/***
 *** Version Methods
 ***/
Bob Halley's avatar
Bob Halley committed
403 404 405

void
dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
406

407 408 409
	/*
	 * Open the current version for reading.
	 */
410

Bob Halley's avatar
Bob Halley committed
411
	REQUIRE(DNS_DB_VALID(db));
412
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
413
	REQUIRE(versionp != NULL && *versionp == NULL);
Bob Halley's avatar
Bob Halley committed
414 415 416 417

	(db->methods->currentversion)(db, versionp);
}

418
isc_result_t
Bob Halley's avatar
Bob Halley committed
419
dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
420

421 422 423 424
	/*
	 * Open a new version for reading and writing.
	 */

Bob Halley's avatar
Bob Halley committed
425
	REQUIRE(DNS_DB_VALID(db));
426
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
427
	REQUIRE(versionp != NULL && *versionp == NULL);
Bob Halley's avatar
Bob Halley committed
428 429 430 431

	return ((db->methods->newversion)(db, versionp));
}

Bob Halley's avatar
Bob Halley committed
432 433 434 435 436 437 438 439 440 441 442
void
dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
		     dns_dbversion_t **targetp)
{
	/*
	 * Attach '*targetp' to 'source'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
	REQUIRE(source != NULL);
443
	REQUIRE(targetp != NULL && *targetp == NULL);
Bob Halley's avatar
Bob Halley committed
444 445 446 447

	(db->methods->attachversion)(db, source, targetp);

	ENSURE(*targetp != NULL);
448
}
Bob Halley's avatar
Bob Halley committed
449

Bob Halley's avatar
Bob Halley committed
450
void
451 452 453
dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
		    isc_boolean_t commit)
{
454
	dns_dbonupdatelistener_t *listener;
455

456 457 458 459
	/*
	 * Close version '*versionp'.
	 */

Bob Halley's avatar
Bob Halley committed
460
	REQUIRE(DNS_DB_VALID(db));
461
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
462 463 464
	REQUIRE(versionp != NULL && *versionp != NULL);

	(db->methods->closeversion)(db, versionp, commit);
Bob Halley's avatar
Bob Halley committed
465

466 467 468 469 470 471 472
	if (commit == ISC_TRUE) {
		for (listener = ISC_LIST_HEAD(db->update_listeners);
		     listener != NULL;
		     listener = ISC_LIST_NEXT(listener, link))
			listener->onupdate(db, listener->onupdate_arg);
	}

473
	ENSURE(*versionp == NULL);
Bob Halley's avatar
Bob Halley committed
474 475
}

476 477 478
/***
 *** Node Methods
 ***/
Bob Halley's avatar
Bob Halley committed
479

480
isc_result_t
Bob Halley's avatar
Bob Halley committed
481 482 483
dns_db_findnode(dns_db_t *db, dns_name_t *name,
		isc_boolean_t create, dns_dbnode_t **nodep)
{
484 485 486 487 488

	/*
	 * Find the node with name 'name'.
	 */

Bob Halley's avatar
Bob Halley committed
489
	REQUIRE(DNS_DB_VALID(db));
490
	REQUIRE(nodep != NULL && *nodep == NULL);
Bob Halley's avatar
Bob Halley committed
491

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
	if (db->methods->findnode != NULL)
		return ((db->methods->findnode)(db, name, create, nodep));
	else
		return ((db->methods->findnodeext)(db, name, create,
						   NULL, NULL, nodep));
}

isc_result_t
dns_db_findnodeext(dns_db_t *db, dns_name_t *name,
		   isc_boolean_t create, dns_clientinfomethods_t *methods,
		   dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep)
{
	/*
	 * Find the node with name 'name', passing 'arg' to the database
	 * implementation.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(nodep != NULL && *nodep == NULL);

	if (db->methods->findnodeext != NULL)
		return ((db->methods->findnodeext)(db, name, create,
						   methods, clientinfo, nodep));
	else
		return ((db->methods->findnode)(db, name, create, nodep));
Bob Halley's avatar
Bob Halley committed
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
isc_result_t
dns_db_findnsec3node(dns_db_t *db, dns_name_t *name,
		     isc_boolean_t create, dns_dbnode_t **nodep)
{

	/*
	 * Find the node with name 'name'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(nodep != NULL && *nodep == NULL);

	return ((db->methods->findnsec3node)(db, name, create, nodep));
}

534
isc_result_t
Bob Halley's avatar
Bob Halley committed
535
dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
536
	    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
Bob Halley's avatar
Bob Halley committed
537
	    dns_dbnode_t **nodep, dns_name_t *foundname,
Bob Halley's avatar
Bob Halley committed
538
	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
Bob Halley's avatar
lint  
Bob Halley committed
539
{
540 541 542 543 544 545
	/*
	 * Find the best match for 'name' and 'type' in version 'version'
	 * of 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
546
	REQUIRE(type != dns_rdatatype_rrsig);
547
	REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL));
548
	REQUIRE(dns_name_hasbuffer(foundname));
549
	REQUIRE(rdataset == NULL ||
550 551
		(DNS_RDATASET_VALID(rdataset) &&
		 ! dns_rdataset_isassociated(rdataset)));
Bob Halley's avatar
Bob Halley committed
552 553
	REQUIRE(sigrdataset == NULL ||
		(DNS_RDATASET_VALID(sigrdataset) &&
554
		 ! dns_rdataset_isassociated(sigrdataset)));
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
	if (db->methods->find != NULL)
		return ((db->methods->find)(db, name, version, type,
					    options, now, nodep, foundname,
					    rdataset, sigrdataset));
	else
		return ((db->methods->findext)(db, name, version, type,
					       options, now, nodep, foundname,
					       NULL, NULL,
					       rdataset, sigrdataset));
}

isc_result_t
dns_db_findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
	       dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
	       dns_dbnode_t **nodep, dns_name_t *foundname,
	       dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{

	/*
	 * Find the best match for 'name' and 'type' in version 'version'
	 * of 'db', passing in 'arg'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(type != dns_rdatatype_rrsig);
	REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL));
	REQUIRE(dns_name_hasbuffer(foundname));
	REQUIRE(rdataset == NULL ||
		(DNS_RDATASET_VALID(rdataset) &&
		 ! dns_rdataset_isassociated(rdataset)));
	REQUIRE(sigrdataset == NULL ||
		(DNS_RDATASET_VALID(sigrdataset) &&
		 ! dns_rdataset_isassociated(sigrdataset)));

	if (db->methods->findext != NULL)
		return ((db->methods->findext)(db, name, version, type,
					       options, now, nodep, foundname,
					       methods, clientinfo,
					       rdataset, sigrdataset));
	else
		return ((db->methods->find)(db, name, version, type,
					    options, now, nodep, foundname,
					    rdataset, sigrdataset));
Bob Halley's avatar
Bob Halley committed
600 601
}

602
isc_result_t
Bob Halley's avatar
Bob Halley committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
dns_db_findzonecut(dns_db_t *db, dns_name_t *name,
		   unsigned int options, isc_stdtime_t now,
		   dns_dbnode_t **nodep, dns_name_t *foundname,
		   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
	/*
	 * Find the deepest known zonecut which encloses 'name' in 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
	REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL));
	REQUIRE(dns_name_hasbuffer(foundname));
	REQUIRE(sigrdataset == NULL ||
		(DNS_RDATASET_VALID(sigrdataset) &&
618
		 ! dns_rdataset_isassociated(sigrdataset)));
Bob Halley's avatar
Bob Halley committed
619 620 621 622 623

	return ((db->methods->findzonecut)(db, name, options, now, nodep,
					   foundname, rdataset, sigrdataset));
}

Bob Halley's avatar
Bob Halley committed
624 625 626
void
dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {

627 628 629 630
	/*
	 * Attach *targetp to source.
	 */

Bob Halley's avatar
Bob Halley committed
631
	REQUIRE(DNS_DB_VALID(db));
632 633
	REQUIRE(source != NULL);
	REQUIRE(targetp != NULL && *targetp == NULL);
Bob Halley's avatar
Bob Halley committed
634 635 636 637 638 639 640

	(db->methods->attachnode)(db, source, targetp);
}

void
dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) {

641 642 643 644
	/*
	 * Detach *nodep from its node.
	 */

Bob Halley's avatar
Bob Halley committed
645
	REQUIRE(DNS_DB_VALID(db));
646
	REQUIRE(nodep != NULL && *nodep != NULL);
Bob Halley's avatar
Bob Halley committed
647 648

	(db->methods->detachnode)(db, nodep);
649 650

	ENSURE(*nodep == NULL);
Bob Halley's avatar
Bob Halley committed
651 652
}

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
void
dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
		    dns_dbnode_t **targetp)
{
	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(targetp != NULL && *targetp == NULL);
	/*
	 * This doesn't check the implementation magic.  If we find that
	 * we need such checks in future then this will be done in the
	 * method.
	 */
	REQUIRE(sourcep != NULL && *sourcep != NULL);

	UNUSED(db);

	if (db->methods->transfernode == NULL) {
Automatic Updater's avatar
Automatic Updater committed
669 670
		*targetp = *sourcep;
		*sourcep = NULL;
671
	} else
Automatic Updater's avatar
Automatic Updater committed
672
		(db->methods->transfernode)(db, sourcep, targetp);
673 674 675 676

	ENSURE(*sourcep == NULL);
}

677
isc_result_t
Bob Halley's avatar
Bob Halley committed
678 679 680 681 682 683 684 685 686 687 688 689 690
dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {

	/*
	 * Mark as stale all records at 'node' which expire at or before 'now'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
	REQUIRE(node != NULL);

	return ((db->methods->expirenode)(db, node, now));
}

Bob Halley's avatar
Bob Halley committed
691 692 693 694 695 696 697 698 699 700 701 702 703
void
dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
	/*
	 * Print a textual representation of the contents of the node to
	 * 'out'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(node != NULL);

	(db->methods->printnode)(db, node, out);
}

Bob Halley's avatar
Bob Halley committed
704 705 706 707
/***
 *** DB Iterator Creation
 ***/

708
isc_result_t
709
dns_db_createiterator(dns_db_t *db, unsigned int flags,
Bob Halley's avatar
Bob Halley committed
710 711 712 713 714 715 716 717 718
		      dns_dbiterator_t **iteratorp)
{
	/*
	 * Create an iterator for version 'version' of 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(iteratorp != NULL && *iteratorp == NULL);

719
	return (db->methods->createiterator(db, flags, iteratorp));
Bob Halley's avatar
Bob Halley committed
720 721
}

722 723 724 725
/***
 *** Rdataset Methods
 ***/

726
isc_result_t
Bob Halley's avatar
Bob Halley committed
727
dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
Bob Halley's avatar
Bob Halley committed
728
		    dns_rdatatype_t type, dns_rdatatype_t covers,
Bob Halley's avatar
Bob Halley committed
729 730
		    isc_stdtime_t now, dns_rdataset_t *rdataset,
		    dns_rdataset_t *sigrdataset)
Bob Halley's avatar
Bob Halley committed
731 732
{
	REQUIRE(DNS_DB_VALID(db));
733 734
	REQUIRE(node != NULL);
	REQUIRE(DNS_RDATASET_VALID(rdataset));
735
	REQUIRE(! dns_rdataset_isassociated(rdataset));
736
	REQUIRE(covers == 0 || type == dns_rdatatype_rrsig);
Bob Halley's avatar
Bob Halley committed
737
	REQUIRE(type != dns_rdatatype_any);
Bob Halley's avatar
Bob Halley committed
738 739
	REQUIRE(sigrdataset == NULL ||
		(DNS_RDATASET_VALID(sigrdataset) &&
740
		 ! dns_rdataset_isassociated(sigrdataset)));
Bob Halley's avatar
Bob Halley committed
741

742 743 744
	return ((db->methods->findrdataset)(db, node, version, type,
					    covers, now, rdataset,
					    sigrdataset));
Bob Halley's avatar
Bob Halley committed
745 746
}

747
isc_result_t
Bob Halley's avatar
Bob Halley committed
748
dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
749
		    isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
Bob Halley's avatar
Bob Halley committed
750 751 752 753 754 755 756 757 758
{
	/*
	 * Make '*iteratorp' an rdataset iteratator for all rdatasets at
	 * 'node' in version 'version' of 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(iteratorp != NULL && *iteratorp == NULL);

759 760
	return ((db->methods->allrdatasets)(db, node, version, now,
					    iteratorp));
Bob Halley's avatar
Bob Halley committed
761 762
}

763
isc_result_t
Bob Halley's avatar
Bob Halley committed
764
dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
765
		   isc_stdtime_t now, dns_rdataset_t *rdataset,
Bob Halley's avatar
Bob Halley committed
766
		   unsigned int options, dns_rdataset_t *addedrdataset)
Bob Halley's avatar
Bob Halley committed
767
{
768 769 770 771
	/*
	 * Add 'rdataset' to 'node' in version 'version' of 'db'.
	 */

Bob Halley's avatar
Bob Halley committed
772
	REQUIRE(DNS_DB_VALID(db));
773
	REQUIRE(node != NULL);
774
	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
Bob Halley's avatar
Bob Halley committed
775
		((db->attributes & DNS_DBATTR_CACHE) != 0 &&
Bob Halley's avatar
Bob Halley committed
776
		 version == NULL && (options & DNS_DBADD_MERGE) == 0));
777 778
	REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
		(options & DNS_DBADD_MERGE) != 0);
779
	REQUIRE(DNS_RDATASET_VALID(rdataset));
780
	REQUIRE(dns_rdataset_isassociated(rdataset));
781
	REQUIRE(rdataset->rdclass == db->rdclass);
782 783
	REQUIRE(addedrdataset == NULL ||
		(DNS_RDATASET_VALID(addedrdataset) &&
784
		 ! dns_rdataset_isassociated(addedrdataset)));
Bob Halley's avatar
Bob Halley committed
785

786
	return ((db->methods->addrdataset)(db, node, version, now, rdataset,
Bob Halley's avatar
Bob Halley committed
787
					   options, addedrdataset));
Bob Halley's avatar
Bob Halley committed
788 789
}

790
isc_result_t
Bob Halley's avatar
Bob Halley committed
791 792
dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
			dns_dbversion_t *version, dns_rdataset_t *rdataset,
793
			unsigned int options, dns_rdataset_t *newrdataset)
Bob Halley's avatar
Bob Halley committed
794 795 796 797 798 799 800 801
{
	/*
	 * Remove any rdata in 'rdataset' from 'node' in version 'version' of
	 * 'db'.
	 */

	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(node != NULL);
Bob Halley's avatar
lint  
Bob Halley committed
802
	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
Bob Halley's avatar
Bob Halley committed
803
	REQUIRE(DNS_RDATASET_VALID(rdataset));
804
	REQUIRE(dns_rdataset_isassociated(rdataset));
Bob Halley's avatar
Bob Halley committed
805 806 807
	REQUIRE(rdataset->rdclass == db->rdclass);
	REQUIRE(newrdataset == NULL ||
		(DNS_RDATASET_VALID(newrdataset) &&
808
		 ! dns_rdataset_isassociated(newrdataset)));
Bob Halley's avatar
Bob Halley committed
809 810

	return ((db->methods->subtractrdataset)(db, node, version, rdataset,
811
						options, newrdataset));
Bob Halley's avatar
Bob Halley committed
812 813
}

814
isc_result_t
Bob Halley's avatar
Bob Halley committed
815
dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
816 817
		      dns_dbversion_t *version, dns_rdatatype_t type,
		      dns_rdatatype_t covers)
Bob Halley's avatar
Bob Halley committed
818
{
819 820 821 822 823
	/*
	 * Make it so that no rdataset of type 'type' exists at 'node' in
	 * version version 'version' of 'db'.
	 */

Bob Halley's avatar
Bob Halley committed
824
	REQUIRE(DNS_DB_VALID(db));
825
	REQUIRE(node != NULL);
826 827
	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
Bob Halley's avatar
Bob Halley committed
828

829 830
	return ((db->methods->deleterdataset)(db, node, version,
					      type, covers));
Bob Halley's avatar
Bob Halley committed
831
}
832

Automatic Updater's avatar
Automatic Updater committed
833
void
834 835 836 837 838 839 840
dns_db_overmem(dns_db_t *db, isc_boolean_t overmem) {

	REQUIRE(DNS_DB_VALID(db));

	(db->methods->overmem)(db, overmem);
}

841 842 843 844 845 846
isc_result_t
dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp)
{
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;
847
	dns_rdata_t rdata = DNS_RDATA_INIT;
848 849
	isc_buffer_t buffer;

850
	REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
851

852 853 854 855 856 857 858
	result = dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node);
	if (result != ISC_R_SUCCESS)
		return (result);

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
				     (isc_stdtime_t)0, &rdataset, NULL);
Automatic Updater's avatar
Automatic Updater committed
859
	if (result != ISC_R_SUCCESS)
860
		goto freenode;
861

862
	result = dns_rdataset_first(&rdataset);
Automatic Updater's avatar
Automatic Updater committed
863
	if (result != ISC_R_SUCCESS)
864 865
		goto freerdataset;
	dns_rdataset_current(&rdataset, &rdata);
866
	result = dns_rdataset_next(&rdataset);
867
	INSIST(result == ISC_R_NOMORE);
868 869 870 871 872 873 874 875 876 877 878

	INSIST(rdata.length > 20);
	isc_buffer_init(&buffer, rdata.data, rdata.length);
	isc_buffer_add(&buffer, rdata.length);
	isc_buffer_forward(&buffer, rdata.length - 20);
	*serialp = isc_buffer_getuint32(&buffer);

	result = ISC_R_SUCCESS;

 freerdataset:
	dns_rdataset_disassociate(&rdataset);
879

880 881 882 883
 freenode:
	dns_db_detachnode(db, &node);
	return (result);
}
884 885 886 887 888 889 890

unsigned int
dns_db_nodecount(dns_db_t *db) {
	REQUIRE(DNS_DB_VALID(db));

	return ((db->methods->nodecount)(db));
}
891

892
size_t
893 894 895 896
dns_db_hashsize(dns_db_t *db) {
	REQUIRE(DNS_DB_VALID(db));

	if (db->methods->hashsize == NULL)
897
		return (0);
898 899 900 901

	return ((db->methods->hashsize)(db));
}

902 903 904 905 906 907 908
void
dns_db_settask(dns_db_t *db, isc_task_t *task) {
	REQUIRE(DNS_DB_VALID(db));

	(db->methods->settask)(db, task);
}

909 910 911 912 913 914 915 916 917
isc_result_t
dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
		isc_mem_t *mctx, dns_dbimplementation_t **dbimp)
{
	dns_dbimplementation_t *imp;

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

918 919
	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);

920 921 922 923 924 925
	RWLOCK(&implock, isc_rwlocktype_write);
	imp = impfind(name);
	if (imp != NULL) {
		RWUNLOCK(&implock, isc_rwlocktype_write);
		return (ISC_R_EXISTS);
	}
Automatic Updater's avatar
Automatic Updater committed
926

927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
	imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
	if (imp == NULL) {
		RWUNLOCK(&implock, isc_rwlocktype_write);
		return (ISC_R_NOMEMORY);
	}
	imp->name = name;
	imp->create = create;
	imp->mctx = NULL;
	imp->driverarg = driverarg;
	isc_mem_attach(mctx, &imp->mctx);
	ISC_LINK_INIT(imp, link);
	ISC_LIST_APPEND(implementations, imp, link);
	RWUNLOCK(&implock, isc_rwlocktype_write);

	*dbimp = imp;

	return (ISC_R_SUCCESS);
}

void
dns_db_unregister(dns_dbimplementation_t **dbimp) {
	dns_dbimplementation_t *imp;
	isc_mem_t *mctx;

	REQUIRE(dbimp != NULL && *dbimp != NULL);

953 954
	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);

955
	imp = *dbimp;
956
	*dbimp = NULL;
957 958 959 960 961 962
	RWLOCK(&implock, isc_rwlocktype_write);
	ISC_LIST_UNLINK(implementations, imp, link);
	mctx = imp->mctx;
	isc_mem_put(mctx, imp, sizeof(dns_dbimplementation_t));
	isc_mem_detach(&mctx);
	RWUNLOCK(&implock, isc_rwlocktype_write);
963
	ENSURE(*dbimp == NULL);
964
}
965 966

isc_result_t
967
dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
968 969 970 971
	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(dns_db_iszone(db) == ISC_TRUE);
	REQUIRE(nodep != NULL && *nodep == NULL);

972 973
	if (db->methods->getoriginnode != NULL)
		return ((db->methods->getoriginnode)(db, nodep));
974 975 976

	return (ISC_R_NOTFOUND);
}
977

978 979 980 981 982 983 984 985 986 987
dns_stats_t *
dns_db_getrrsetstats(dns_db_t *db) {
	REQUIRE(DNS_DB_VALID(db));

	if (db->methods->getrrsetstats != NULL)
		return ((db->methods->getrrsetstats)(db));

	return (NULL);
}

988 989 990 991 992 993 994 995 996 997
isc_result_t
dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
	REQUIRE(DNS_DB_VALID(db));

	if (db->methods->setcachestats != NULL)
		return ((db->methods->setcachestats)(db, stats));

	return (ISC_R_NOTIMPLEMENTED);
}

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
isc_result_t
dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
			  dns_hash_t *hash, isc_uint8_t *flags,
			  isc_uint16_t *iterations,
			  unsigned char *salt, size_t *salt_length)
{
	REQUIRE(DNS_DB_VALID(db));
	REQUIRE(dns_db_iszone(db) == ISC_TRUE);

	if (db->methods->getnsec3parameters != NULL)
		return ((db->methods->getnsec3parameters)(db, version, hash,
							  flags, iterations,
							  salt, salt_length));

	return (ISC_R_NOTFOUND);
}

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
isc_result_t
dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
		      isc_stdtime_t resign)
{
	if (db->methods->setsigningtime != NULL)
		return ((db->methods->setsigningtime)(db, rdataset, resign));
	return (ISC_R_NOTIMPLEMENTED);
}

isc_result_t
dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name)
{
	if (db->methods->getsigningtime != NULL)
		return ((db->methods->getsigningtime)(db, rdataset, name));
	return (ISC_R_NOTFOUND);
}

void
1033 1034
dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
		dns_dbversion_t *version)
1035 1036
{
	if (db->methods->resigned != NULL)
Mark Andrews's avatar
Mark Andrews committed
1037
		(db->methods->resigned)(db, rdataset, version);
1038
}
1039

1040 1041 1042 1043 1044
/*
 * Attach a database to policy zone databases.
 * This should only happen when the caller has already ensured that
 * it is dealing with a database that understands response policy zones.
 */
1045
void
1046 1047 1048
dns_db_rpz_attach(dns_db_t *db, dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num) {
	REQUIRE(db->methods->rpz_attach != NULL);
	(db->methods->rpz_attach)(db, rpzs, rpz_num);
1049 1050
}

1051 1052 1053 1054 1055 1056 1057 1058
/*
 * Finish loading a response policy zone.
 */
isc_result_t
dns_db_rpz_ready(dns_db_t *db) {
	if (db->methods->rpz_ready == NULL)
		return (ISC_R_SUCCESS);
	return ((db->methods->rpz_ready)(db));
1059
}
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111

/**
 * Attach a notify-on-update function the database
 */
isc_result_t
dns_db_updatenotify_register(dns_db_t *db,
			     dns_dbupdate_callback_t fn,
			     void *fn_arg)
{
	dns_dbonupdatelistener_t *listener;

	REQUIRE(db != NULL);
	REQUIRE(fn != NULL);

	listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t));
	if (listener == NULL)
		return (ISC_R_NOMEMORY);

	listener->onupdate = fn;
	listener->onupdate_arg = fn_arg;

	ISC_LINK_INIT(listener, link);
	ISC_LIST_APPEND(db->update_listeners, listener, link);

	return (ISC_R_SUCCESS);
}

isc_result_t
dns_db_updatenotify_unregister(dns_db_t *db,
			       dns_dbupdate_callback_t fn,
			       void *fn_arg)
{
	dns_dbonupdatelistener_t *listener;

	REQUIRE(db != NULL);

	for (listener = ISC_LIST_HEAD(db->update_listeners);
	     listener != NULL;
	     listener = ISC_LIST_NEXT(listener, link))
	{
		if ((listener->onupdate == fn) &&
		    (listener->onupdate_arg == fn_arg))
		{
			ISC_LIST_UNLINK(db->update_listeners, listener, link);
			isc_mem_put(db->mctx, listener,
				    sizeof(dns_dbonupdatelistener_t));
			return (ISC_R_SUCCESS);
		}
	}

	return (ISC_R_NOTFOUND);
}