sdb.c 37.9 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 8 9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10 11
 */

12
/*! \file */
13

14
#include <inttypes.h>
15
#include <stdbool.h>
Brian Wellington's avatar
Brian Wellington committed
16 17
#include <string.h>

18 19
#include <isc/buffer.h>
#include <isc/lex.h>
20
#include <isc/log.h>
21 22 23 24
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/once.h>
#include <isc/print.h>
25
#include <isc/refcount.h>
26 27 28
#include <isc/region.h>
#include <isc/util.h>

29
#include <dns/callbacks.h>
30
#include <dns/db.h>
31
#include <dns/dbiterator.h>
32
#include <dns/fixedname.h>
33
#include <dns/log.h>
34 35 36 37 38 39 40 41 42 43 44
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dns/sdb.h>
#include <dns/types.h>

#include "rdatalist_p.h"

45
struct dns_sdbimplementation {
46
	const dns_sdbmethods_t *methods;
Evan Hunt's avatar
Evan Hunt committed
47 48 49 50
	void *driverdata;
	unsigned int flags;
	isc_mem_t *mctx;
	isc_mutex_t driverlock;
51
	dns_dbimplementation_t *dbimp;
52
};
53 54 55

struct dns_sdb {
	/* Unlocked */
Evan Hunt's avatar
Evan Hunt committed
56 57
	dns_db_t common;
	char *zone;
58
	dns_sdbimplementation_t *implementation;
Evan Hunt's avatar
Evan Hunt committed
59
	void *dbdata;
60 61

	/* Atomic */
62
	isc_refcount_t references;
63 64 65 66
};

struct dns_sdblookup {
	/* Unlocked */
67
	unsigned int magic;
Evan Hunt's avatar
Evan Hunt committed
68
	dns_sdb_t *sdb;
69 70 71 72 73
	ISC_LIST(dns_rdatalist_t) lists;
	ISC_LIST(isc_buffer_t) buffers;
	dns_name_t *name;
	ISC_LINK(dns_sdblookup_t) link;
	dns_rdatacallbacks_t callbacks;
74 75

	/* Atomic */
76
	isc_refcount_t references;
77 78
};

79 80 81
typedef struct dns_sdblookup dns_sdbnode_t;

struct dns_sdballnodes {
82 83 84 85
	dns_dbiterator_t common;
	ISC_LIST(dns_sdbnode_t) nodelist;
	dns_sdbnode_t *current;
	dns_sdbnode_t *origin;
86 87 88 89
};

typedef dns_sdballnodes_t sdb_dbiterator_t;

90
typedef struct sdb_rdatasetiter {
91
	dns_rdatasetiter_t common;
Evan Hunt's avatar
Evan Hunt committed
92
	dns_rdatalist_t *current;
93 94
} sdb_rdatasetiter_t;

95
#define SDB_MAGIC ISC_MAGIC('S', 'D', 'B', '-')
96

97
/*%
98 99 100
 * Note that "impmagic" is not the first four bytes of the struct, so
 * ISC_MAGIC_VALID cannot be used.
 */
101
#define VALID_SDB(sdb) ((sdb) != NULL && (sdb)->common.impmagic == SDB_MAGIC)
102

Evan Hunt's avatar
Evan Hunt committed
103
#define SDBLOOKUP_MAGIC	      ISC_MAGIC('S', 'D', 'B', 'L')
104
#define VALID_SDBLOOKUP(sdbl) ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
Evan Hunt's avatar
Evan Hunt committed
105
#define VALID_SDBNODE(sdbn)   VALID_SDBLOOKUP(sdbn)
106

107
/* These values are taken from RFC1537 */
Evan Hunt's avatar
Evan Hunt committed
108 109 110 111
#define SDB_DEFAULT_REFRESH 28800U  /* 8 hours */
#define SDB_DEFAULT_RETRY   7200U   /* 2 hours */
#define SDB_DEFAULT_EXPIRE  604800U /* 7 days */
#define SDB_DEFAULT_MINIMUM 86400U  /* 1 day */
112 113

/* This is a reasonable value */
114
#define SDB_DEFAULT_TTL (60 * 60 * 24)
115

116
#ifdef __COVERITY__
Evan Hunt's avatar
Evan Hunt committed
117
#define MAYBE_LOCK(sdb)	  LOCK(&sdb->implementation->driverlock)
118
#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
119
#else /* ifdef __COVERITY__ */
120 121 122 123 124
#define MAYBE_LOCK(sdb)                                          \
	do {                                                     \
		unsigned int flags = sdb->implementation->flags; \
		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)       \
			LOCK(&sdb->implementation->driverlock);  \
125 126
	} while (0)

127 128 129 130 131
#define MAYBE_UNLOCK(sdb)                                         \
	do {                                                      \
		unsigned int flags = sdb->implementation->flags;  \
		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)        \
			UNLOCK(&sdb->implementation->driverlock); \
132
	} while (0)
133
#endif /* ifdef __COVERITY__ */
134

135 136
static int dummy;

Ondřej Surý's avatar
Ondřej Surý committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
static isc_result_t
dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
	       void *driverarg, dns_db_t **dbp);

static isc_result_t
findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);

static isc_result_t
createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);

static void
destroynode(dns_sdbnode_t *node);

static void
detachnode(dns_db_t *db, dns_dbnode_t **targetp);

static void
list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
		dns_rdataset_t *rdataset);

static void
dbiterator_destroy(dns_dbiterator_t **iteratorp);
static isc_result_t
dbiterator_first(dns_dbiterator_t *iterator);
static isc_result_t
dbiterator_last(dns_dbiterator_t *iterator);
static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name);
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator);
static isc_result_t
dbiterator_next(dns_dbiterator_t *iterator);
static isc_result_t
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
		   dns_name_t *name);
static isc_result_t
dbiterator_pause(dns_dbiterator_t *iterator);
static isc_result_t
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
179 180

static dns_dbiteratormethods_t dbiterator_methods = {
181 182 183
	dbiterator_destroy, dbiterator_first, dbiterator_last,
	dbiterator_seek,    dbiterator_prev,  dbiterator_next,
	dbiterator_current, dbiterator_pause, dbiterator_origin
184
};
185

Ondřej Surý's avatar
Ondřej Surý committed
186 187 188 189 190 191 192 193
static void
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
static isc_result_t
rdatasetiter_first(dns_rdatasetiter_t *iterator);
static isc_result_t
rdatasetiter_next(dns_rdatasetiter_t *iterator);
static void
rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset);
194 195

static dns_rdatasetitermethods_t rdatasetiter_methods = {
196
	rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
197 198 199 200 201 202 203
	rdatasetiter_current
};

/*
 * Functions used by implementors of simple databases
 */
isc_result_t
204
dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
205
		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
Evan Hunt's avatar
Evan Hunt committed
206
		 dns_sdbimplementation_t **sdbimp) {
207
	dns_sdbimplementation_t *imp;
Evan Hunt's avatar
Evan Hunt committed
208
	isc_result_t result;
209 210

	REQUIRE(drivername != NULL);
211
	REQUIRE(methods != NULL);
212
	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
213 214
	REQUIRE(mctx != NULL);
	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
215 216 217
	REQUIRE((flags &
		 ~(DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA |
		   DNS_SDBFLAG_THREADSAFE | DNS_SDBFLAG_DNS64)) == 0);
218

219 220 221 222 223 224
	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
	imp->methods = methods;
	imp->driverdata = driverdata;
	imp->flags = flags;
	imp->mctx = NULL;
	isc_mem_attach(mctx, &imp->mctx);
Ondřej Surý's avatar
Ondřej Surý committed
225
	isc_mutex_init(&imp->driverlock);
226

227 228 229
	imp->dbimp = NULL;
	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
				 &imp->dbimp);
230
	if (result != ISC_R_SUCCESS) {
231
		goto cleanup_mutex;
232
	}
233
	*sdbimp = imp;
234 235

	return (ISC_R_SUCCESS);
236

237
cleanup_mutex:
238
	isc_mutex_destroy(&imp->driverlock);
239 240
	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
	return (result);
241 242 243
}

void
Evan Hunt's avatar
Evan Hunt committed
244
dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
245
	dns_sdbimplementation_t *imp;
246

247 248 249
	REQUIRE(sdbimp != NULL && *sdbimp != NULL);

	imp = *sdbimp;
250
	*sdbimp = NULL;
251
	dns_db_unregister(&imp->dbimp);
252
	isc_mutex_destroy(&imp->driverlock);
253

254
	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_sdbimplementation_t));
255 256
}

257
static inline unsigned int
Evan Hunt's avatar
Evan Hunt committed
258
initial_size(unsigned int len) {
Brian Wellington's avatar
Brian Wellington committed
259
	unsigned int size;
260

261 262
	for (size = 1024; size < (64 * 1024); size *= 2) {
		if (len < size) {
263
			return (size);
264 265
		}
	}
266
	return (65535);
267 268
}

269
isc_result_t
270
dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
Evan Hunt's avatar
Evan Hunt committed
271 272
		 dns_ttl_t ttl, const unsigned char *rdatap,
		 unsigned int rdlen) {
273
	dns_rdatalist_t *rdatalist;
Evan Hunt's avatar
Evan Hunt committed
274 275 276 277
	dns_rdata_t *rdata;
	isc_buffer_t *rdatabuf = NULL;
	isc_mem_t *mctx;
	isc_region_t region;
278 279 280 281 282

	mctx = lookup->sdb->common.mctx;

	rdatalist = ISC_LIST_HEAD(lookup->lists);
	while (rdatalist != NULL) {
283
		if (rdatalist->type == typeval) {
284
			break;
285
		}
286 287 288 289 290
		rdatalist = ISC_LIST_NEXT(rdatalist, link);
	}

	if (rdatalist == NULL) {
		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
291
		dns_rdatalist_init(rdatalist);
292 293 294 295
		rdatalist->rdclass = lookup->sdb->common.rdclass;
		rdatalist->type = typeval;
		rdatalist->ttl = ttl;
		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
296
	} else if (rdatalist->ttl != ttl) {
297
		return (DNS_R_BADTTL);
298
	}
299 300

	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
301

302
	isc_buffer_allocate(mctx, &rdatabuf, rdlen);
303 304 305 306
	DE_CONST(rdatap, region.base);
	region.length = rdlen;
	isc_buffer_copyregion(rdatabuf, &region);
	isc_buffer_usedregion(rdatabuf, &region);
307
	dns_rdata_init(rdata);
308 309 310 311 312
	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
			     &region);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);

313
	return (ISC_R_SUCCESS);
314
}
Automatic Updater's avatar
Automatic Updater committed
315

316 317
isc_result_t
dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
Evan Hunt's avatar
Evan Hunt committed
318 319 320
	      const char *data) {
	unsigned int datalen;
	dns_rdatatype_t typeval;
Mark Andrews's avatar
Mark Andrews committed
321
	isc_textregion_t r;
Evan Hunt's avatar
Evan Hunt committed
322 323 324 325 326
	isc_lex_t *lex = NULL;
	isc_result_t result;
	unsigned char *p = NULL;
	unsigned int size = 0; /* Init to suppress compiler warning */
	isc_mem_t *mctx;
327
	dns_sdbimplementation_t *imp;
Evan Hunt's avatar
Evan Hunt committed
328 329 330
	const dns_name_t *origin;
	isc_buffer_t b;
	isc_buffer_t rb;
331 332 333 334 335 336 337

	REQUIRE(VALID_SDBLOOKUP(lookup));
	REQUIRE(type != NULL);
	REQUIRE(data != NULL);

	mctx = lookup->sdb->common.mctx;

Mark Andrews's avatar
Mark Andrews committed
338
	DE_CONST(type, r.base);
339
	r.length = strlen(type);
Mark Andrews's avatar
Mark Andrews committed
340
	result = dns_rdatatype_fromtext(&typeval, &r);
341
	if (result != ISC_R_SUCCESS) {
342
		return (result);
343
	}
344

345
	imp = lookup->sdb->implementation;
346
	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
347
		origin = &lookup->sdb->common.origin;
348
	} else {
349
		origin = dns_rootname;
350
	}
351

352
	result = isc_lex_create(mctx, 64, &lex);
353
	if (result != ISC_R_SUCCESS) {
354
		goto failure;
355
	}
356

357 358
	datalen = strlen(data);
	size = initial_size(datalen);
359
	do {
360
		isc_buffer_constinit(&b, data, datalen);
361
		isc_buffer_add(&b, datalen);
362
		result = isc_lex_openbuffer(lex, &b);
363
		if (result != ISC_R_SUCCESS) {
364
			goto failure;
365
		}
366

367
		if (size >= 65535) {
368
			size = 65535;
369
		}
370 371
		p = isc_mem_get(mctx, size);
		isc_buffer_init(&rb, p, size);
372 373
		result = dns_rdata_fromtext(NULL, lookup->sdb->common.rdclass,
					    typeval, lex, origin, 0, mctx, &rb,
374
					    &lookup->callbacks);
375
		if (result != ISC_R_NOSPACE) {
376
			break;
377
		}
378

379 380 381
		/*
		 * Is the RR too big?
		 */
382
		if (size >= 65535) {
383
			break;
384
		}
385 386
		isc_mem_put(mctx, p, size);
		p = NULL;
387 388 389
		size *= 2;
	} while (result == ISC_R_NOSPACE);

390
	if (result != ISC_R_SUCCESS) {
391
		goto failure;
392
	}
393

394
	result = dns_sdb_putrdata(lookup, typeval, ttl, isc_buffer_base(&rb),
395
				  isc_buffer_usedlength(&rb));
396
failure:
397
	if (p != NULL) {
398
		isc_mem_put(mctx, p, size);
399 400
	}
	if (lex != NULL) {
401
		isc_lex_destroy(&lex);
402
	}
403 404 405 406

	return (result);
}

407
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
408 409 410 411 412
getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
	dns_name_t *newname;
	const dns_name_t *origin;
	dns_fixedname_t fnewname;
	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
413
	dns_sdbimplementation_t *imp = sdb->implementation;
Evan Hunt's avatar
Evan Hunt committed
414 415 416 417
	dns_sdbnode_t *sdbnode;
	isc_mem_t *mctx = sdb->common.mctx;
	isc_buffer_t b;
	isc_result_t result;
418

419
	newname = dns_fixedname_initname(&fnewname);
420

421
	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
422
		origin = &sdb->common.origin;
423
	} else {
424
		origin = dns_rootname;
425
	}
426
	isc_buffer_constinit(&b, name, strlen(name));
427 428
	isc_buffer_add(&b, strlen(name));

429
	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
430
	if (result != ISC_R_SUCCESS) {
431
		return (result);
432
	}
433 434 435 436 437 438 439 440 441 442 443

	if (allnodes->common.relative_names) {
		/* All names are relative to the root */
		unsigned int nlabels = dns_name_countlabels(newname);
		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
	}

	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
		sdbnode = NULL;
		result = createnode(sdb, &sdbnode);
444
		if (result != ISC_R_SUCCESS) {
445
			return (result);
446
		}
447 448
		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
		dns_name_init(sdbnode->name, NULL);
449
		dns_name_dup(newname, mctx, sdbnode->name);
450 451
		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
		if (allnodes->origin == NULL &&
452
		    dns_name_equal(newname, &sdb->common.origin)) {
453
			allnodes->origin = sdbnode;
454
		}
455
	}
456 457 458 459 460 461
	*nodep = sdbnode;
	return (ISC_R_SUCCESS);
}

isc_result_t
dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
Evan Hunt's avatar
Evan Hunt committed
462 463
		   const char *type, dns_ttl_t ttl, const char *data) {
	isc_result_t result;
464 465
	dns_sdbnode_t *sdbnode = NULL;
	result = getnode(allnodes, name, &sdbnode);
466
	if (result != ISC_R_SUCCESS) {
467
		return (result);
468
	}
469
	return (dns_sdb_putrr(sdbnode, type, ttl, data));
470
}
471

472 473
isc_result_t
dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
474
		      dns_rdatatype_t type, dns_ttl_t ttl, const void *rdata,
Evan Hunt's avatar
Evan Hunt committed
475 476
		      unsigned int rdlen) {
	isc_result_t result;
477 478
	dns_sdbnode_t *sdbnode = NULL;
	result = getnode(allnodes, name, &sdbnode);
479
	if (result != ISC_R_SUCCESS) {
480
		return (result);
481
	}
482
	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
483 484
}

485 486
isc_result_t
dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
Evan Hunt's avatar
Evan Hunt committed
487
	       uint32_t serial) {
488
	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
Evan Hunt's avatar
Evan Hunt committed
489
	int n;
490 491 492 493

	REQUIRE(mname != NULL);
	REQUIRE(rname != NULL);

494 495
	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u", mname, rname,
		     serial, SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
496
		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
497
	if (n >= (int)sizeof(str) || n < 0) {
498
		return (ISC_R_NOSPACE);
499
	}
500 501 502 503 504 505 506 507
	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
}

/*
 * DB routines
 */

static void
Evan Hunt's avatar
Evan Hunt committed
508
attach(dns_db_t *source, dns_db_t **targetp) {
509
	dns_sdb_t *sdb = (dns_sdb_t *)source;
510 511 512

	REQUIRE(VALID_SDB(sdb));

513
	isc_refcount_increment(&sdb->references);
514 515 516 517 518

	*targetp = source;
}

static void
Evan Hunt's avatar
Evan Hunt committed
519
destroy(dns_sdb_t *sdb) {
520
	dns_sdbimplementation_t *imp = sdb->implementation;
521

522 523
	isc_refcount_destroy(&sdb->references);

524 525
	if (imp->methods->destroy != NULL) {
		MAYBE_LOCK(sdb);
526
		imp->methods->destroy(sdb->zone, imp->driverdata, &sdb->dbdata);
527 528
		MAYBE_UNLOCK(sdb);
	}
529

530
	isc_mem_free(sdb->common.mctx, sdb->zone);
531 532 533 534

	sdb->common.magic = 0;
	sdb->common.impmagic = 0;

535
	dns_name_free(&sdb->common.origin, sdb->common.mctx);
536

537
	isc_mem_putanddetach(&sdb->common.mctx, sdb, sizeof(dns_sdb_t));
538 539 540
}

static void
Evan Hunt's avatar
Evan Hunt committed
541
detach(dns_db_t **dbp) {
542 543 544 545 546
	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);

	REQUIRE(VALID_SDB(sdb));

	*dbp = NULL;
547 548 549 550

	if (isc_refcount_decrement(&sdb->references) == 1) {
		destroy(sdb);
	}
551 552 553
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
554
beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
555
	UNUSED(db);
556
	UNUSED(callbacks);
557 558 559 560
	return (ISC_R_NOTIMPLEMENTED);
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
561
endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
562
	UNUSED(db);
563
	UNUSED(callbacks);
564 565 566 567
	return (ISC_R_NOTIMPLEMENTED);
}

static isc_result_t
568
dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
Evan Hunt's avatar
Evan Hunt committed
569
     dns_masterformat_t masterformat) {
570 571 572
	UNUSED(db);
	UNUSED(version);
	UNUSED(filename);
573
	UNUSED(masterformat);
574 575 576 577
	return (ISC_R_NOTIMPLEMENTED);
}

static void
Evan Hunt's avatar
Evan Hunt committed
578
currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
579 580 581 582
	REQUIRE(versionp != NULL && *versionp == NULL);

	UNUSED(db);

583
	*versionp = (void *)&dummy;
584 585 586 587
	return;
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
588
newversion(dns_db_t *db, dns_dbversion_t **versionp) {
589 590 591 592 593 594 595
	UNUSED(db);
	UNUSED(versionp);

	return (ISC_R_NOTIMPLEMENTED);
}

static void
Evan Hunt's avatar
Evan Hunt committed
596 597
attachversion(dns_db_t *db, dns_dbversion_t *source,
	      dns_dbversion_t **targetp) {
598
	REQUIRE(source != NULL && source == (void *)&dummy);
599
	REQUIRE(targetp != NULL && *targetp == NULL);
600 601

	UNUSED(db);
602
	*targetp = source;
603 604 605 606
	return;
}

static void
Evan Hunt's avatar
Evan Hunt committed
607
closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
608
	REQUIRE(versionp != NULL && *versionp == (void *)&dummy);
609
	REQUIRE(!commit);
610 611 612 613 614 615 616 617

	UNUSED(db);
	UNUSED(commit);

	*versionp = NULL;
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
618
createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
619 620 621 622 623 624 625 626
	dns_sdbnode_t *node;

	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));

	node->sdb = NULL;
	attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
	ISC_LIST_INIT(node->lists);
	ISC_LIST_INIT(node->buffers);
627 628
	ISC_LINK_INIT(node, link);
	node->name = NULL;
629
	dns_rdatacallbacks_init(&node->callbacks);
630 631 632

	isc_refcount_init(&node->references, 1);

633 634 635 636 637 638 639
	node->magic = SDBLOOKUP_MAGIC;

	*nodep = node;
	return (ISC_R_SUCCESS);
}

static void
Evan Hunt's avatar
Evan Hunt committed
640
destroynode(dns_sdbnode_t *node) {
641
	dns_rdatalist_t *list;
Evan Hunt's avatar
Evan Hunt committed
642 643 644 645
	dns_rdata_t *rdata;
	isc_buffer_t *b;
	dns_sdb_t *sdb;
	isc_mem_t *mctx;
646 647 648

	sdb = node->sdb;
	mctx = sdb->common.mctx;
649 650 651 652 653 654

	while (!ISC_LIST_EMPTY(node->lists)) {
		list = ISC_LIST_HEAD(node->lists);
		while (!ISC_LIST_EMPTY(list->rdata)) {
			rdata = ISC_LIST_HEAD(list->rdata);
			ISC_LIST_UNLINK(list->rdata, rdata, link);
655
			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
656 657
		}
		ISC_LIST_UNLINK(node->lists, list, link);
658
		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
659 660 661 662 663 664 665 666
	}

	while (!ISC_LIST_EMPTY(node->buffers)) {
		b = ISC_LIST_HEAD(node->buffers);
		ISC_LIST_UNLINK(node->buffers, b, link);
		isc_buffer_free(&b);
	}

667 668 669 670
	if (node->name != NULL) {
		dns_name_free(node->name, mctx);
		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
	}
671

672
	node->magic = 0;
673
	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
674
	detach((dns_db_t **)(void *)&sdb);
675 676
}

Mark Andrews's avatar
Mark Andrews committed
677
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
678 679 680 681 682 683
getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
	dns_sdb_t *sdb = (dns_sdb_t *)db;
	dns_sdbnode_t *node = NULL;
	isc_result_t result;
	isc_buffer_t b;
	char namestr[DNS_NAME_MAXTEXT + 1];
Mark Andrews's avatar
Mark Andrews committed
684
	dns_sdbimplementation_t *imp;
Evan Hunt's avatar
Evan Hunt committed
685 686
	dns_name_t relname;
	dns_name_t *name;
Mark Andrews's avatar
Mark Andrews committed
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

	REQUIRE(VALID_SDB(sdb));
	REQUIRE(nodep != NULL && *nodep == NULL);

	imp = sdb->implementation;
	name = &sdb->common.origin;

	if (imp->methods->lookup2 != NULL) {
		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
			dns_name_init(&relname, NULL);
			name = &relname;
		}
	} else {
		isc_buffer_init(&b, namestr, sizeof(namestr));
		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
			dns_name_init(&relname, NULL);
			result = dns_name_totext(&relname, true, &b);
			if (result != ISC_R_SUCCESS) {
				return (result);
			}
		} else {
			result = dns_name_totext(name, true, &b);
			if (result != ISC_R_SUCCESS) {
				return (result);
			}
		}
		isc_buffer_putuint8(&b, 0);
	}

	result = createnode(sdb, &node);
	if (result != ISC_R_SUCCESS) {
		return (result);
	}

	MAYBE_LOCK(sdb);
	if (imp->methods->lookup2 != NULL) {
		result = imp->methods->lookup2(&sdb->common.origin, name,
					       sdb->dbdata, node, NULL, NULL);
	} else {
		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
					      node, NULL, NULL);
	}
	MAYBE_UNLOCK(sdb);
	if (result != ISC_R_SUCCESS &&
Evan Hunt's avatar
Evan Hunt committed
731 732
	    !(result == ISC_R_NOTFOUND && imp->methods->authority != NULL))
	{
Mark Andrews's avatar
Mark Andrews committed
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
		destroynode(node);
		return (result);
	}

	if (imp->methods->authority != NULL) {
		MAYBE_LOCK(sdb);
		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
		MAYBE_UNLOCK(sdb);
		if (result != ISC_R_SUCCESS) {
			destroynode(node);
			return (result);
		}
	}

	*nodep = node;
	return (ISC_R_SUCCESS);
}

751
static isc_result_t
752
findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
753
	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
Evan Hunt's avatar
Evan Hunt committed
754 755 756 757 758 759 760
	    dns_dbnode_t **nodep) {
	dns_sdb_t *sdb = (dns_sdb_t *)db;
	dns_sdbnode_t *node = NULL;
	isc_result_t result;
	isc_buffer_t b;
	char namestr[DNS_NAME_MAXTEXT + 1];
	bool isorigin;
761
	dns_sdbimplementation_t *imp;
Evan Hunt's avatar
Evan Hunt committed
762 763
	dns_name_t relname;
	unsigned int labels;
764 765 766 767 768

	REQUIRE(VALID_SDB(sdb));
	REQUIRE(nodep != NULL && *nodep == NULL);

	UNUSED(name);
769
	UNUSED(create);
770

771 772
	imp = sdb->implementation;

773
	isorigin = dns_name_equal(name, &sdb->common.origin);
774

775 776 777 778 779 780 781 782
	if (imp->methods->lookup2 != NULL) {
		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
			labels = dns_name_countlabels(name) -
				 dns_name_countlabels(&db->origin);
			dns_name_init(&relname, NULL);
			dns_name_getlabelsequence(name, 0, labels, &relname);
			name = &relname;
		}
783
	} else {
784 785 786 787 788 789
		isc_buffer_init(&b, namestr, sizeof(namestr));
		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
			labels = dns_name_countlabels(name) -
				 dns_name_countlabels(&db->origin);
			dns_name_init(&relname, NULL);
			dns_name_getlabelsequence(name, 0, labels, &relname);
790
			result = dns_name_totext(&relname, true, &b);
791
			if (result != ISC_R_SUCCESS) {
792
				return (result);
793
			}
794
		} else {
795
			result = dns_name_totext(name, true, &b);
796
			if (result != ISC_R_SUCCESS) {
797
				return (result);
798
			}
799 800
		}
		isc_buffer_putuint8(&b, 0);
801
	}
802 803

	result = createnode(sdb, &node);
804
	if (result != ISC_R_SUCCESS) {
805
		return (result);
806
	}
807

808
	MAYBE_LOCK(sdb);
809
	if (imp->methods->lookup2 != NULL) {
810 811 812
		result = imp->methods->lookup2(&sdb->common.origin, name,
					       sdb->dbdata, node, methods,
					       clientinfo);
813
	} else {
814 815
		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
					      node, methods, clientinfo);
816
	}
817
	MAYBE_UNLOCK(sdb);
818
	if (result != ISC_R_SUCCESS && !(result == ISC_R_NOTFOUND && isorigin &&
Evan Hunt's avatar
Evan Hunt committed
819 820
					 imp->methods->authority != NULL))
	{
821 822 823 824
		destroynode(node);
		return (result);
	}

825
	if (isorigin && imp->methods->authority != NULL) {
826
		MAYBE_LOCK(sdb);
827
		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
828
		MAYBE_UNLOCK(sdb);
829 830 831 832 833
		if (result != ISC_R_SUCCESS) {
			destroynode(node);
			return (result);
		}
	}
Automatic Updater's avatar
Automatic Updater committed
834

835 836 837 838 839
	*nodep = node;
	return (ISC_R_SUCCESS);
}

static isc_result_t
840
findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
841 842 843
	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,
Evan Hunt's avatar
Evan Hunt committed
844 845 846
	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
	dns_sdb_t *sdb = (dns_sdb_t *)db;
	dns_dbnode_t *node = NULL;
847
	dns_fixedname_t fname;
Evan Hunt's avatar
Evan Hunt committed
848 849 850 851 852 853
	dns_rdataset_t xrdataset;
	dns_name_t *xname;
	unsigned int nlabels, olabels;
	isc_result_t result;
	unsigned int i;
	unsigned int flags;
854 855 856

	REQUIRE(VALID_SDB(sdb));
	REQUIRE(nodep == NULL || *nodep == NULL);
857
	REQUIRE(version == NULL || version == (void *)&dummy);
858 859 860

	UNUSED(options);

861
	if (!dns_name_issubdomain(name, &db->origin)) {
862
		return (DNS_R_NXDOMAIN);
863
	}
864 865 866 867

	olabels = dns_name_countlabels(&db->origin);
	nlabels = dns_name_countlabels(name);

868
	xname = dns_fixedname_initname(&fname);
869

870 871
	if (rdataset == NULL) {
		dns_rdataset_init(&xrdataset);
872
		rdataset = &xrdataset;
873
	}
874 875

	result = DNS_R_NXDOMAIN;
876 877 878
	flags = sdb->implementation->flags;
	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
	for (; i <= nlabels; i++) {
879 880 881 882
		/*
		 * Look up the next label.
		 */
		dns_name_getlabelsequence(name, nlabels - i, i, xname);
883 884
		result = findnodeext(db, xname, false, methods, clientinfo,
				     &node);
885 886 887 888
		if (result == ISC_R_NOTFOUND) {
			/*
			 * No data at zone apex?
			 */
889
			if (i == olabels) {