sdb.c revision 1.3
1/*	$NetBSD: sdb.c,v 1.3 2019/01/09 16:55:12 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14/*! \file */
15
16#include <config.h>
17
18#include <inttypes.h>
19#include <stdbool.h>
20#include <string.h>
21
22#include <isc/buffer.h>
23#include <isc/lex.h>
24#include <isc/log.h>
25#include <isc/magic.h>
26#include <isc/mem.h>
27#include <isc/once.h>
28#include <isc/print.h>
29#include <isc/region.h>
30#include <isc/util.h>
31
32#include <dns/callbacks.h>
33#include <dns/db.h>
34#include <dns/dbiterator.h>
35#include <dns/fixedname.h>
36#include <dns/log.h>
37#include <dns/rdata.h>
38#include <dns/rdatalist.h>
39#include <dns/rdataset.h>
40#include <dns/rdatasetiter.h>
41#include <dns/rdatatype.h>
42#include <dns/result.h>
43#include <dns/sdb.h>
44#include <dns/types.h>
45
46#include "rdatalist_p.h"
47
48struct dns_sdbimplementation {
49	const dns_sdbmethods_t		*methods;
50	void				*driverdata;
51	unsigned int			flags;
52	isc_mem_t			*mctx;
53	isc_mutex_t			driverlock;
54	dns_dbimplementation_t		*dbimp;
55};
56
57struct dns_sdb {
58	/* Unlocked */
59	dns_db_t			common;
60	char				*zone;
61	dns_sdbimplementation_t		*implementation;
62	void				*dbdata;
63	isc_mutex_t			lock;
64	/* Locked */
65	unsigned int			references;
66};
67
68struct dns_sdblookup {
69	/* Unlocked */
70	unsigned int			magic;
71	dns_sdb_t			*sdb;
72	ISC_LIST(dns_rdatalist_t)	lists;
73	ISC_LIST(isc_buffer_t)		buffers;
74	dns_name_t			*name;
75	ISC_LINK(dns_sdblookup_t)	link;
76	isc_mutex_t			lock;
77	dns_rdatacallbacks_t		callbacks;
78	/* Locked */
79	unsigned int			references;
80};
81
82typedef struct dns_sdblookup dns_sdbnode_t;
83
84struct dns_sdballnodes {
85	dns_dbiterator_t		common;
86	ISC_LIST(dns_sdbnode_t)		nodelist;
87	dns_sdbnode_t			*current;
88	dns_sdbnode_t			*origin;
89};
90
91typedef dns_sdballnodes_t sdb_dbiterator_t;
92
93typedef struct sdb_rdatasetiter {
94	dns_rdatasetiter_t		common;
95	dns_rdatalist_t			*current;
96} sdb_rdatasetiter_t;
97
98#define SDB_MAGIC		ISC_MAGIC('S', 'D', 'B', '-')
99
100/*%
101 * Note that "impmagic" is not the first four bytes of the struct, so
102 * ISC_MAGIC_VALID cannot be used.
103 */
104#define VALID_SDB(sdb)		((sdb) != NULL && \
105				 (sdb)->common.impmagic == SDB_MAGIC)
106
107#define SDBLOOKUP_MAGIC		ISC_MAGIC('S','D','B','L')
108#define VALID_SDBLOOKUP(sdbl)	ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
109#define VALID_SDBNODE(sdbn)	VALID_SDBLOOKUP(sdbn)
110
111/* These values are taken from RFC1537 */
112#define SDB_DEFAULT_REFRESH	28800U		/* 8 hours */
113#define SDB_DEFAULT_RETRY	7200U		/* 2 hours */
114#define SDB_DEFAULT_EXPIRE	604800U		/* 7 days */
115#define SDB_DEFAULT_MINIMUM	86400U		/* 1 day */
116
117/* This is a reasonable value */
118#define SDB_DEFAULT_TTL		(60 * 60 * 24)
119
120#ifdef __COVERITY__
121#define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
122#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
123#else
124#define MAYBE_LOCK(sdb)							\
125	do {								\
126		unsigned int flags = sdb->implementation->flags;	\
127		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
128			LOCK(&sdb->implementation->driverlock);		\
129	} while (/*CONSTCOND*/0)
130
131#define MAYBE_UNLOCK(sdb)						\
132	do {								\
133		unsigned int flags = sdb->implementation->flags;	\
134		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
135			UNLOCK(&sdb->implementation->driverlock);	\
136	} while (/*CONSTCOND*/0)
137#endif
138
139static int dummy;
140
141static isc_result_t dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin,
142				   dns_dbtype_t type, dns_rdataclass_t rdclass,
143				   unsigned int argc, char *argv[],
144				   void *driverarg, dns_db_t **dbp);
145
146static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
147				 dns_dbversion_t *version,
148				 dns_rdatatype_t type, dns_rdatatype_t covers,
149				 isc_stdtime_t now, dns_rdataset_t *rdataset,
150				 dns_rdataset_t *sigrdataset);
151
152static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
153
154static void destroynode(dns_sdbnode_t *node);
155
156static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
157
158
159static void list_tordataset(dns_rdatalist_t *rdatalist,
160			    dns_db_t *db, dns_dbnode_t *node,
161			    dns_rdataset_t *rdataset);
162
163static void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
164static isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
165static isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
166static isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
167					const dns_name_t *name);
168static isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
169static isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
170static isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
171					   dns_dbnode_t **nodep,
172					   dns_name_t *name);
173static isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
174static isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
175					  dns_name_t *name);
176
177static dns_dbiteratormethods_t dbiterator_methods = {
178	dbiterator_destroy,
179	dbiterator_first,
180	dbiterator_last,
181	dbiterator_seek,
182	dbiterator_prev,
183	dbiterator_next,
184	dbiterator_current,
185	dbiterator_pause,
186	dbiterator_origin
187};
188
189static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
190static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
191static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
192static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
193					     dns_rdataset_t *rdataset);
194
195static dns_rdatasetitermethods_t rdatasetiter_methods = {
196	rdatasetiter_destroy,
197	rdatasetiter_first,
198	rdatasetiter_next,
199	rdatasetiter_current
200};
201
202/*
203 * Functions used by implementors of simple databases
204 */
205isc_result_t
206dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
207		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
208		 dns_sdbimplementation_t **sdbimp)
209{
210	dns_sdbimplementation_t *imp;
211	isc_result_t result;
212
213	REQUIRE(drivername != NULL);
214	REQUIRE(methods != NULL);
215	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
216	REQUIRE(mctx != NULL);
217	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
218	REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
219			   DNS_SDBFLAG_RELATIVERDATA |
220			   DNS_SDBFLAG_THREADSAFE|
221			   DNS_SDBFLAG_DNS64)) == 0);
222
223	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
224	if (imp == NULL)
225		return (ISC_R_NOMEMORY);
226	imp->methods = methods;
227	imp->driverdata = driverdata;
228	imp->flags = flags;
229	imp->mctx = NULL;
230	isc_mem_attach(mctx, &imp->mctx);
231	isc_mutex_init(&imp->driverlock);
232
233	imp->dbimp = NULL;
234	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
235				 &imp->dbimp);
236	if (result != ISC_R_SUCCESS)
237		goto cleanup_mutex;
238	*sdbimp = imp;
239
240	return (ISC_R_SUCCESS);
241
242 cleanup_mutex:
243	isc_mutex_destroy(&imp->driverlock);
244	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
245	return (result);
246}
247
248void
249dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
250	dns_sdbimplementation_t *imp;
251	isc_mem_t *mctx;
252
253	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
254
255	imp = *sdbimp;
256	dns_db_unregister(&imp->dbimp);
257	isc_mutex_destroy(&imp->driverlock);
258
259	mctx = imp->mctx;
260	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
261	isc_mem_detach(&mctx);
262
263	*sdbimp = NULL;
264}
265
266static inline unsigned int
267initial_size(unsigned int len) {
268	unsigned int size;
269
270	for (size = 1024; size < (64 * 1024); size *= 2)
271		if (len < size)
272			return (size);
273	return (65535);
274}
275
276isc_result_t
277dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
278		 dns_ttl_t ttl, const unsigned char *rdatap,
279		 unsigned int rdlen)
280{
281	dns_rdatalist_t *rdatalist;
282	dns_rdata_t *rdata;
283	isc_buffer_t *rdatabuf = NULL;
284	isc_result_t result;
285	isc_mem_t *mctx;
286	isc_region_t region;
287
288	mctx = lookup->sdb->common.mctx;
289
290	rdatalist = ISC_LIST_HEAD(lookup->lists);
291	while (rdatalist != NULL) {
292		if (rdatalist->type == typeval)
293			break;
294		rdatalist = ISC_LIST_NEXT(rdatalist, link);
295	}
296
297	if (rdatalist == NULL) {
298		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
299		if (rdatalist == NULL)
300			return (ISC_R_NOMEMORY);
301		dns_rdatalist_init(rdatalist);
302		rdatalist->rdclass = lookup->sdb->common.rdclass;
303		rdatalist->type = typeval;
304		rdatalist->ttl = ttl;
305		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
306	} else
307		if (rdatalist->ttl != ttl)
308			return (DNS_R_BADTTL);
309
310	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
311	if (rdata == NULL)
312		return (ISC_R_NOMEMORY);
313
314	result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
315	if (result != ISC_R_SUCCESS)
316		goto failure;
317	DE_CONST(rdatap, region.base);
318	region.length = rdlen;
319	isc_buffer_copyregion(rdatabuf, &region);
320	isc_buffer_usedregion(rdatabuf, &region);
321	dns_rdata_init(rdata);
322	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
323			     &region);
324	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
325	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
326	rdata = NULL;
327
328 failure:
329	if (rdata != NULL)
330		isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
331	return (result);
332}
333
334isc_result_t
335dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
336	      const char *data)
337{
338	unsigned int datalen;
339	dns_rdatatype_t typeval;
340	isc_textregion_t r;
341	isc_lex_t *lex = NULL;
342	isc_result_t result;
343	unsigned char *p = NULL;
344	unsigned int size = 0; /* Init to suppress compiler warning */
345	isc_mem_t *mctx;
346	dns_sdbimplementation_t *imp;
347	const dns_name_t *origin;
348	isc_buffer_t b;
349	isc_buffer_t rb;
350
351	REQUIRE(VALID_SDBLOOKUP(lookup));
352	REQUIRE(type != NULL);
353	REQUIRE(data != NULL);
354
355	mctx = lookup->sdb->common.mctx;
356
357	DE_CONST(type, r.base);
358	r.length = strlen(type);
359	result = dns_rdatatype_fromtext(&typeval, &r);
360	if (result != ISC_R_SUCCESS)
361		return (result);
362
363	imp = lookup->sdb->implementation;
364	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
365		origin = &lookup->sdb->common.origin;
366	else
367		origin = dns_rootname;
368
369	result = isc_lex_create(mctx, 64, &lex);
370	if (result != ISC_R_SUCCESS)
371		goto failure;
372
373	datalen = strlen(data);
374	size = initial_size(datalen);
375	do {
376		isc_buffer_constinit(&b, data, datalen);
377		isc_buffer_add(&b, datalen);
378		result = isc_lex_openbuffer(lex, &b);
379		if (result != ISC_R_SUCCESS)
380			goto failure;
381
382		if (size >= 65535)
383			size = 65535;
384		p = isc_mem_get(mctx, size);
385		if (p == NULL) {
386			result = ISC_R_NOMEMORY;
387			goto failure;
388		}
389		isc_buffer_init(&rb, p, size);
390		result = dns_rdata_fromtext(NULL,
391					    lookup->sdb->common.rdclass,
392					    typeval, lex,
393					    origin, 0,
394					    mctx, &rb,
395					    &lookup->callbacks);
396		if (result != ISC_R_NOSPACE)
397			break;
398
399		/*
400		 * Is the RR too big?
401		 */
402		if (size >= 65535)
403			break;
404		isc_mem_put(mctx, p, size);
405		p = NULL;
406		size *= 2;
407	} while (result == ISC_R_NOSPACE);
408
409	if (result != ISC_R_SUCCESS)
410		goto failure;
411
412	result = dns_sdb_putrdata(lookup, typeval, ttl,
413				  isc_buffer_base(&rb),
414				  isc_buffer_usedlength(&rb));
415 failure:
416	if (p != NULL)
417		isc_mem_put(mctx, p, size);
418	if (lex != NULL)
419		isc_lex_destroy(&lex);
420
421	return (result);
422}
423
424static isc_result_t
425getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
426	dns_name_t *newname;
427	const dns_name_t *origin;
428	dns_fixedname_t fnewname;
429	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
430	dns_sdbimplementation_t *imp = sdb->implementation;
431	dns_sdbnode_t *sdbnode;
432	isc_mem_t *mctx = sdb->common.mctx;
433	isc_buffer_t b;
434	isc_result_t result;
435
436	newname = dns_fixedname_initname(&fnewname);
437
438	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
439		origin = &sdb->common.origin;
440	else
441		origin = dns_rootname;
442	isc_buffer_constinit(&b, name, strlen(name));
443	isc_buffer_add(&b, strlen(name));
444
445	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
446	if (result != ISC_R_SUCCESS)
447		return (result);
448
449	if (allnodes->common.relative_names) {
450		/* All names are relative to the root */
451		unsigned int nlabels = dns_name_countlabels(newname);
452		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
453	}
454
455	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
456	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
457		sdbnode = NULL;
458		result = createnode(sdb, &sdbnode);
459		if (result != ISC_R_SUCCESS)
460			return (result);
461		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
462		if (sdbnode->name == NULL) {
463			destroynode(sdbnode);
464			return (ISC_R_NOMEMORY);
465		}
466		dns_name_init(sdbnode->name, NULL);
467		result = dns_name_dup(newname, mctx, sdbnode->name);
468		if (result != ISC_R_SUCCESS) {
469			isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
470			destroynode(sdbnode);
471			return (result);
472		}
473		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
474		if (allnodes->origin == NULL &&
475		    dns_name_equal(newname, &sdb->common.origin))
476			allnodes->origin = sdbnode;
477	}
478	*nodep = sdbnode;
479	return (ISC_R_SUCCESS);
480}
481
482isc_result_t
483dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
484		   const char *type, dns_ttl_t ttl, const char *data)
485{
486	isc_result_t result;
487	dns_sdbnode_t *sdbnode = NULL;
488	result = getnode(allnodes, name, &sdbnode);
489	if (result != ISC_R_SUCCESS)
490		return (result);
491	return (dns_sdb_putrr(sdbnode, type, ttl, data));
492}
493
494isc_result_t
495dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
496		      dns_rdatatype_t type, dns_ttl_t ttl,
497		      const void *rdata, unsigned int rdlen)
498{
499	isc_result_t result;
500	dns_sdbnode_t *sdbnode = NULL;
501	result = getnode(allnodes, name, &sdbnode);
502	if (result != ISC_R_SUCCESS)
503		return (result);
504	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
505}
506
507isc_result_t
508dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
509	       uint32_t serial)
510{
511	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
512	int n;
513
514	REQUIRE(mname != NULL);
515	REQUIRE(rname != NULL);
516
517	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
518		     mname, rname, serial,
519		     SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
520		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
521	if (n >= (int)sizeof(str) || n < 0)
522		return (ISC_R_NOSPACE);
523	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
524}
525
526/*
527 * DB routines
528 */
529
530static void
531attach(dns_db_t *source, dns_db_t **targetp) {
532	dns_sdb_t *sdb = (dns_sdb_t *) source;
533
534	REQUIRE(VALID_SDB(sdb));
535
536	LOCK(&sdb->lock);
537	REQUIRE(sdb->references > 0);
538	sdb->references++;
539	UNLOCK(&sdb->lock);
540
541	*targetp = source;
542}
543
544static void
545destroy(dns_sdb_t *sdb) {
546	isc_mem_t *mctx;
547	dns_sdbimplementation_t *imp = sdb->implementation;
548
549	mctx = sdb->common.mctx;
550
551	if (imp->methods->destroy != NULL) {
552		MAYBE_LOCK(sdb);
553		imp->methods->destroy(sdb->zone, imp->driverdata,
554				      &sdb->dbdata);
555		MAYBE_UNLOCK(sdb);
556	}
557
558	isc_mem_free(mctx, sdb->zone);
559	isc_mutex_destroy(&sdb->lock);
560
561	sdb->common.magic = 0;
562	sdb->common.impmagic = 0;
563
564	dns_name_free(&sdb->common.origin, mctx);
565
566	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
567	isc_mem_detach(&mctx);
568}
569
570static void
571detach(dns_db_t **dbp) {
572	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
573	bool need_destroy = false;
574
575	REQUIRE(VALID_SDB(sdb));
576	LOCK(&sdb->lock);
577	REQUIRE(sdb->references > 0);
578	sdb->references--;
579	if (sdb->references == 0)
580		need_destroy = true;
581	UNLOCK(&sdb->lock);
582
583	if (need_destroy)
584		destroy(sdb);
585
586	*dbp = NULL;
587}
588
589static isc_result_t
590beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
591	UNUSED(db);
592	UNUSED(callbacks);
593	return (ISC_R_NOTIMPLEMENTED);
594}
595
596static isc_result_t
597endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
598	UNUSED(db);
599	UNUSED(callbacks);
600	return (ISC_R_NOTIMPLEMENTED);
601}
602
603static isc_result_t
604dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
605     dns_masterformat_t masterformat) {
606	UNUSED(db);
607	UNUSED(version);
608	UNUSED(filename);
609	UNUSED(masterformat);
610	return (ISC_R_NOTIMPLEMENTED);
611}
612
613static void
614currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
615	REQUIRE(versionp != NULL && *versionp == NULL);
616
617	UNUSED(db);
618
619	*versionp = (void *) &dummy;
620	return;
621}
622
623static isc_result_t
624newversion(dns_db_t *db, dns_dbversion_t **versionp) {
625	UNUSED(db);
626	UNUSED(versionp);
627
628	return (ISC_R_NOTIMPLEMENTED);
629}
630
631static void
632attachversion(dns_db_t *db, dns_dbversion_t *source,
633	      dns_dbversion_t **targetp)
634{
635	REQUIRE(source != NULL && source == (void *) &dummy);
636	REQUIRE(targetp != NULL && *targetp == NULL);
637
638	UNUSED(db);
639	*targetp = source;
640	return;
641}
642
643static void
644closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
645	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
646	REQUIRE(commit == false);
647
648	UNUSED(db);
649	UNUSED(commit);
650
651	*versionp = NULL;
652}
653
654static isc_result_t
655createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
656	dns_sdbnode_t *node;
657
658	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
659	if (node == NULL)
660		return (ISC_R_NOMEMORY);
661
662	node->sdb = NULL;
663	attach((dns_db_t *)sdb, (dns_db_t **)(void *)&node->sdb);
664	ISC_LIST_INIT(node->lists);
665	ISC_LIST_INIT(node->buffers);
666	ISC_LINK_INIT(node, link);
667	node->name = NULL;
668	isc_mutex_init(&node->lock);
669	dns_rdatacallbacks_init(&node->callbacks);
670	node->references = 1;
671	node->magic = SDBLOOKUP_MAGIC;
672
673	*nodep = node;
674	return (ISC_R_SUCCESS);
675}
676
677static void
678destroynode(dns_sdbnode_t *node) {
679	dns_rdatalist_t *list;
680	dns_rdata_t *rdata;
681	isc_buffer_t *b;
682	dns_sdb_t *sdb;
683	isc_mem_t *mctx;
684
685	sdb = node->sdb;
686	mctx = sdb->common.mctx;
687
688	while (!ISC_LIST_EMPTY(node->lists)) {
689		list = ISC_LIST_HEAD(node->lists);
690		while (!ISC_LIST_EMPTY(list->rdata)) {
691			rdata = ISC_LIST_HEAD(list->rdata);
692			ISC_LIST_UNLINK(list->rdata, rdata, link);
693			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
694		}
695		ISC_LIST_UNLINK(node->lists, list, link);
696		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
697	}
698
699	while (!ISC_LIST_EMPTY(node->buffers)) {
700		b = ISC_LIST_HEAD(node->buffers);
701		ISC_LIST_UNLINK(node->buffers, b, link);
702		isc_buffer_free(&b);
703	}
704
705	if (node->name != NULL) {
706		dns_name_free(node->name, mctx);
707		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
708	}
709	isc_mutex_destroy(&node->lock);
710	node->magic = 0;
711	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
712	detach((dns_db_t **) (void *)&sdb);
713}
714
715static isc_result_t
716findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
717	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
718	    dns_dbnode_t **nodep)
719{
720	dns_sdb_t *sdb = (dns_sdb_t *)db;
721	dns_sdbnode_t *node = NULL;
722	isc_result_t result;
723	isc_buffer_t b;
724	char namestr[DNS_NAME_MAXTEXT + 1];
725	bool isorigin;
726	dns_sdbimplementation_t *imp;
727	dns_name_t relname;
728	unsigned int labels;
729
730	REQUIRE(VALID_SDB(sdb));
731	REQUIRE(create == false);
732	REQUIRE(nodep != NULL && *nodep == NULL);
733
734	UNUSED(name);
735	UNUSED(create);
736
737	imp = sdb->implementation;
738
739	isorigin = dns_name_equal(name, &sdb->common.origin);
740
741	if (imp->methods->lookup2 != NULL) {
742		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
743			labels = dns_name_countlabels(name) -
744				 dns_name_countlabels(&db->origin);
745			dns_name_init(&relname, NULL);
746			dns_name_getlabelsequence(name, 0, labels, &relname);
747			name = &relname;
748		}
749	} else {
750		isc_buffer_init(&b, namestr, sizeof(namestr));
751		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
752
753			labels = dns_name_countlabels(name) -
754				 dns_name_countlabels(&db->origin);
755			dns_name_init(&relname, NULL);
756			dns_name_getlabelsequence(name, 0, labels, &relname);
757			result = dns_name_totext(&relname, true, &b);
758			if (result != ISC_R_SUCCESS)
759				return (result);
760		} else {
761			result = dns_name_totext(name, true, &b);
762			if (result != ISC_R_SUCCESS)
763				return (result);
764		}
765		isc_buffer_putuint8(&b, 0);
766	}
767
768	result = createnode(sdb, &node);
769	if (result != ISC_R_SUCCESS)
770		return (result);
771
772	MAYBE_LOCK(sdb);
773	if (imp->methods->lookup2 != NULL)
774		result = imp->methods->lookup2(&sdb->common.origin, name,
775					       sdb->dbdata, node, methods,
776					       clientinfo);
777	else
778		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
779					      node, methods, clientinfo);
780	MAYBE_UNLOCK(sdb);
781	if (result != ISC_R_SUCCESS &&
782	    !(result == ISC_R_NOTFOUND &&
783	      isorigin && imp->methods->authority != NULL))
784	{
785		destroynode(node);
786		return (result);
787	}
788
789	if (isorigin && imp->methods->authority != NULL) {
790		MAYBE_LOCK(sdb);
791		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
792		MAYBE_UNLOCK(sdb);
793		if (result != ISC_R_SUCCESS) {
794			destroynode(node);
795			return (result);
796		}
797	}
798
799	*nodep = node;
800	return (ISC_R_SUCCESS);
801}
802
803static isc_result_t
804findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
805	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
806	dns_dbnode_t **nodep, dns_name_t *foundname,
807	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
808	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
809{
810	dns_sdb_t *sdb = (dns_sdb_t *)db;
811	dns_dbnode_t *node = NULL;
812	dns_fixedname_t fname;
813	dns_rdataset_t xrdataset;
814	dns_name_t *xname;
815	unsigned int nlabels, olabels;
816	isc_result_t result;
817	unsigned int i;
818	unsigned int flags;
819
820	REQUIRE(VALID_SDB(sdb));
821	REQUIRE(nodep == NULL || *nodep == NULL);
822	REQUIRE(version == NULL || version == (void *) &dummy);
823
824	UNUSED(options);
825
826	if (!dns_name_issubdomain(name, &db->origin))
827		return (DNS_R_NXDOMAIN);
828
829	olabels = dns_name_countlabels(&db->origin);
830	nlabels = dns_name_countlabels(name);
831
832	xname = dns_fixedname_initname(&fname);
833
834	if (rdataset == NULL) {
835		dns_rdataset_init(&xrdataset);
836		rdataset = &xrdataset;
837	}
838
839	result = DNS_R_NXDOMAIN;
840	flags = sdb->implementation->flags;
841	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
842	for (; i <= nlabels; i++) {
843		/*
844		 * Look up the next label.
845		 */
846		dns_name_getlabelsequence(name, nlabels - i, i, xname);
847		result = findnodeext(db, xname, false, methods,
848				     clientinfo, &node);
849		if (result == ISC_R_NOTFOUND) {
850			/*
851			 * No data at zone apex?
852			 */
853			if (i == olabels)
854				return (DNS_R_BADDB);
855			result = DNS_R_NXDOMAIN;
856			continue;
857		}
858		if (result != ISC_R_SUCCESS)
859			return (result);
860
861		/*
862		 * DNS64 zone's don't have DNAME or NS records.
863		 */
864		if ((flags & DNS_SDBFLAG_DNS64) != 0)
865			goto skip;
866
867		/*
868		 * DNS64 zone's don't have DNAME or NS records.
869		 */
870		if ((flags & DNS_SDBFLAG_DNS64) != 0)
871			goto skip;
872
873		/*
874		 * Look for a DNAME at the current label, unless this is
875		 * the qname.
876		 */
877		if (i < nlabels) {
878			result = findrdataset(db, node, version,
879					      dns_rdatatype_dname,
880					      0, now, rdataset, sigrdataset);
881			if (result == ISC_R_SUCCESS) {
882				result = DNS_R_DNAME;
883				break;
884			}
885		}
886
887		/*
888		 * Look for an NS at the current label, unless this is the
889		 * origin or glue is ok.
890		 */
891		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
892			result = findrdataset(db, node, version,
893					      dns_rdatatype_ns,
894					      0, now, rdataset, sigrdataset);
895			if (result == ISC_R_SUCCESS) {
896				if (i == nlabels && type == dns_rdatatype_any)
897				{
898					result = DNS_R_ZONECUT;
899					dns_rdataset_disassociate(rdataset);
900					if (sigrdataset != NULL &&
901					    dns_rdataset_isassociated
902							(sigrdataset)) {
903						dns_rdataset_disassociate
904								(sigrdataset);
905					}
906				} else
907					result = DNS_R_DELEGATION;
908				break;
909			}
910		}
911
912		/*
913		 * If the current name is not the qname, add another label
914		 * and try again.
915		 */
916		if (i < nlabels) {
917			destroynode(node);
918			node = NULL;
919			continue;
920		}
921
922 skip:
923		/*
924		 * If we're looking for ANY, we're done.
925		 */
926		if (type == dns_rdatatype_any) {
927			result = ISC_R_SUCCESS;
928			break;
929		}
930
931		/*
932		 * Look for the qtype.
933		 */
934		result = findrdataset(db, node, version, type,
935				      0, now, rdataset, sigrdataset);
936		if (result == ISC_R_SUCCESS)
937			break;
938
939		/*
940		 * Look for a CNAME
941		 */
942		if (type != dns_rdatatype_cname) {
943			result = findrdataset(db, node, version,
944					      dns_rdatatype_cname,
945					      0, now, rdataset, sigrdataset);
946			if (result == ISC_R_SUCCESS) {
947				result = DNS_R_CNAME;
948				break;
949			}
950		}
951
952		result = DNS_R_NXRRSET;
953		break;
954	}
955
956	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
957		dns_rdataset_disassociate(rdataset);
958
959	if (foundname != NULL) {
960		isc_result_t xresult;
961
962		xresult = dns_name_copy(xname, foundname, NULL);
963		if (xresult != ISC_R_SUCCESS) {
964			if (node != NULL)
965				destroynode(node);
966			if (dns_rdataset_isassociated(rdataset))
967				dns_rdataset_disassociate(rdataset);
968			return (DNS_R_BADDB);
969		}
970	}
971
972	if (nodep != NULL)
973		*nodep = node;
974	else if (node != NULL)
975		detachnode(db, &node);
976
977	return (result);
978}
979
980static isc_result_t
981findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
982	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
983	    dns_name_t *dcname, dns_rdataset_t *rdataset,
984	    dns_rdataset_t *sigrdataset)
985{
986	UNUSED(db);
987	UNUSED(name);
988	UNUSED(options);
989	UNUSED(now);
990	UNUSED(nodep);
991	UNUSED(foundname);
992	UNUSED(dcname);
993	UNUSED(rdataset);
994	UNUSED(sigrdataset);
995
996	return (ISC_R_NOTIMPLEMENTED);
997}
998
999static void
1000attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1001	dns_sdb_t *sdb = (dns_sdb_t *)db;
1002	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1003
1004	REQUIRE(VALID_SDB(sdb));
1005
1006	UNUSED(sdb);
1007
1008	LOCK(&node->lock);
1009	INSIST(node->references > 0);
1010	node->references++;
1011	INSIST(node->references != 0);		/* Catch overflow. */
1012	UNLOCK(&node->lock);
1013
1014	*targetp = source;
1015}
1016
1017static void
1018detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1019	dns_sdb_t *sdb = (dns_sdb_t *)db;
1020	dns_sdbnode_t *node;
1021	bool need_destroy = false;
1022
1023	REQUIRE(VALID_SDB(sdb));
1024	REQUIRE(targetp != NULL && *targetp != NULL);
1025
1026	UNUSED(sdb);
1027
1028	node = (dns_sdbnode_t *)(*targetp);
1029
1030	LOCK(&node->lock);
1031	INSIST(node->references > 0);
1032	node->references--;
1033	if (node->references == 0)
1034		need_destroy = true;
1035	UNLOCK(&node->lock);
1036
1037	if (need_destroy)
1038		destroynode(node);
1039
1040	*targetp = NULL;
1041}
1042
1043static isc_result_t
1044expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1045	UNUSED(db);
1046	UNUSED(node);
1047	UNUSED(now);
1048	INSIST(0);
1049	ISC_UNREACHABLE();
1050}
1051
1052static void
1053printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1054	UNUSED(db);
1055	UNUSED(node);
1056	UNUSED(out);
1057	return;
1058}
1059
1060static isc_result_t
1061createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1062{
1063	dns_sdb_t *sdb = (dns_sdb_t *)db;
1064	sdb_dbiterator_t *sdbiter;
1065	dns_sdbimplementation_t *imp = sdb->implementation;
1066	isc_result_t result;
1067
1068	REQUIRE(VALID_SDB(sdb));
1069
1070	if (imp->methods->allnodes == NULL)
1071		return (ISC_R_NOTIMPLEMENTED);
1072
1073	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1074	    (options & DNS_DB_NONSEC3) != 0)
1075		return (ISC_R_NOTIMPLEMENTED);
1076
1077	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1078	if (sdbiter == NULL)
1079		return (ISC_R_NOMEMORY);
1080
1081	sdbiter->common.methods = &dbiterator_methods;
1082	sdbiter->common.db = NULL;
1083	dns_db_attach(db, &sdbiter->common.db);
1084	sdbiter->common.relative_names = ((options & DNS_DB_RELATIVENAMES) != 0);
1085	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1086	ISC_LIST_INIT(sdbiter->nodelist);
1087	sdbiter->current = NULL;
1088	sdbiter->origin = NULL;
1089
1090	MAYBE_LOCK(sdb);
1091	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1092	MAYBE_UNLOCK(sdb);
1093	if (result != ISC_R_SUCCESS) {
1094		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1095		return (result);
1096	}
1097
1098	if (sdbiter->origin != NULL) {
1099		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1100		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1101	}
1102
1103	*iteratorp = (dns_dbiterator_t *)sdbiter;
1104
1105	return (ISC_R_SUCCESS);
1106}
1107
1108static isc_result_t
1109findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1110	     dns_rdatatype_t type, dns_rdatatype_t covers,
1111	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1112	     dns_rdataset_t *sigrdataset)
1113{
1114	dns_rdatalist_t *list;
1115	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1116
1117	REQUIRE(VALID_SDBNODE(node));
1118
1119	UNUSED(db);
1120	UNUSED(version);
1121	UNUSED(covers);
1122	UNUSED(now);
1123	UNUSED(sigrdataset);
1124
1125	if (type == dns_rdatatype_rrsig)
1126		return (ISC_R_NOTIMPLEMENTED);
1127
1128	list = ISC_LIST_HEAD(sdbnode->lists);
1129	while (list != NULL) {
1130		if (list->type == type)
1131			break;
1132		list = ISC_LIST_NEXT(list, link);
1133	}
1134	if (list == NULL)
1135		return (ISC_R_NOTFOUND);
1136
1137	list_tordataset(list, db, node, rdataset);
1138
1139	return (ISC_R_SUCCESS);
1140}
1141
1142static isc_result_t
1143allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1144	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1145{
1146	sdb_rdatasetiter_t *iterator;
1147
1148	REQUIRE(version == NULL || version == &dummy);
1149
1150	UNUSED(version);
1151	UNUSED(now);
1152
1153	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1154	if (iterator == NULL)
1155		return (ISC_R_NOMEMORY);
1156
1157	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1158	iterator->common.methods = &rdatasetiter_methods;
1159	iterator->common.db = db;
1160	iterator->common.node = NULL;
1161	attachnode(db, node, &iterator->common.node);
1162	iterator->common.version = version;
1163	iterator->common.now = now;
1164
1165	*iteratorp = (dns_rdatasetiter_t *)iterator;
1166
1167	return (ISC_R_SUCCESS);
1168}
1169
1170static isc_result_t
1171addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1172	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1173	    dns_rdataset_t *addedrdataset)
1174{
1175	UNUSED(db);
1176	UNUSED(node);
1177	UNUSED(version);
1178	UNUSED(now);
1179	UNUSED(rdataset);
1180	UNUSED(options);
1181	UNUSED(addedrdataset);
1182
1183	return (ISC_R_NOTIMPLEMENTED);
1184}
1185
1186static isc_result_t
1187subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1188		 dns_rdataset_t *rdataset, unsigned int options,
1189		 dns_rdataset_t *newrdataset)
1190{
1191	UNUSED(db);
1192	UNUSED(node);
1193	UNUSED(version);
1194	UNUSED(rdataset);
1195	UNUSED(options);
1196	UNUSED(newrdataset);
1197
1198	return (ISC_R_NOTIMPLEMENTED);
1199}
1200
1201static isc_result_t
1202deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1203	       dns_rdatatype_t type, dns_rdatatype_t covers)
1204{
1205	UNUSED(db);
1206	UNUSED(node);
1207	UNUSED(version);
1208	UNUSED(type);
1209	UNUSED(covers);
1210
1211	return (ISC_R_NOTIMPLEMENTED);
1212}
1213
1214static bool
1215issecure(dns_db_t *db) {
1216	UNUSED(db);
1217
1218	return (false);
1219}
1220
1221static unsigned int
1222nodecount(dns_db_t *db) {
1223	UNUSED(db);
1224
1225	return (0);
1226}
1227
1228static bool
1229ispersistent(dns_db_t *db) {
1230	UNUSED(db);
1231	return (true);
1232}
1233
1234static void
1235overmem(dns_db_t *db, bool over) {
1236	UNUSED(db);
1237	UNUSED(over);
1238}
1239
1240static void
1241settask(dns_db_t *db, isc_task_t *task) {
1242	UNUSED(db);
1243	UNUSED(task);
1244}
1245
1246
1247static dns_dbmethods_t sdb_methods = {
1248	attach,
1249	detach,
1250	beginload,
1251	endload,
1252	NULL,			/* serialize */
1253	dump,
1254	currentversion,
1255	newversion,
1256	attachversion,
1257	closeversion,
1258	NULL,			/* findnode */
1259	NULL,			/* find */
1260	findzonecut,
1261	attachnode,
1262	detachnode,
1263	expirenode,
1264	printnode,
1265	createiterator,
1266	findrdataset,
1267	allrdatasets,
1268	addrdataset,
1269	subtractrdataset,
1270	deleterdataset,
1271	issecure,
1272	nodecount,
1273	ispersistent,
1274	overmem,
1275	settask,
1276	NULL,			/* getoriginnode */
1277	NULL,			/* transfernode */
1278	NULL,			/* getnsec3parameters */
1279	NULL,			/* findnsec3node */
1280	NULL,			/* setsigningtime */
1281	NULL,			/* getsigningtime */
1282	NULL,			/* resigned */
1283	NULL,			/* isdnssec */
1284	NULL,			/* getrrsetstats */
1285	NULL,			/* rpz_attach */
1286	NULL,			/* rpz_ready */
1287	findnodeext,
1288	findext,
1289	NULL,			/* setcachestats */
1290	NULL,			/* hashsize */
1291	NULL,			/* nodefullname */
1292	NULL,			/* getsize */
1293	NULL,			/* setservestalettl */
1294	NULL,			/* getservestalettl */
1295	NULL			/* setgluecachestats */
1296};
1297
1298static isc_result_t
1299dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
1300	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1301	       void *driverarg, dns_db_t **dbp)
1302{
1303	dns_sdb_t *sdb;
1304	isc_result_t result;
1305	char zonestr[DNS_NAME_MAXTEXT + 1];
1306	isc_buffer_t b;
1307	dns_sdbimplementation_t *imp;
1308
1309	REQUIRE(driverarg != NULL);
1310
1311	imp = driverarg;
1312
1313	if (type != dns_dbtype_zone)
1314		return (ISC_R_NOTIMPLEMENTED);
1315
1316	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1317	if (sdb == NULL)
1318		return (ISC_R_NOMEMORY);
1319	memset(sdb, 0, sizeof(dns_sdb_t));
1320
1321	dns_name_init(&sdb->common.origin, NULL);
1322	sdb->common.attributes = 0;
1323	sdb->common.methods = &sdb_methods;
1324	sdb->common.rdclass = rdclass;
1325	sdb->common.mctx = NULL;
1326	sdb->implementation = imp;
1327
1328	isc_mem_attach(mctx, &sdb->common.mctx);
1329
1330	isc_mutex_init(&sdb->lock);
1331
1332	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1333	if (result != ISC_R_SUCCESS)
1334		goto cleanup_lock;
1335
1336	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1337	result = dns_name_totext(origin, true, &b);
1338	if (result != ISC_R_SUCCESS)
1339		goto cleanup_origin;
1340	isc_buffer_putuint8(&b, 0);
1341
1342	sdb->zone = isc_mem_strdup(mctx, zonestr);
1343	if (sdb->zone == NULL) {
1344		result = ISC_R_NOMEMORY;
1345		goto cleanup_origin;
1346	}
1347
1348	sdb->dbdata = NULL;
1349	if (imp->methods->create != NULL) {
1350		MAYBE_LOCK(sdb);
1351		result = imp->methods->create(sdb->zone, argc, argv,
1352					      imp->driverdata, &sdb->dbdata);
1353		MAYBE_UNLOCK(sdb);
1354		if (result != ISC_R_SUCCESS)
1355			goto cleanup_zonestr;
1356	}
1357
1358	sdb->references = 1;
1359
1360	sdb->common.magic = DNS_DB_MAGIC;
1361	sdb->common.impmagic = SDB_MAGIC;
1362
1363	*dbp = (dns_db_t *)sdb;
1364
1365	return (ISC_R_SUCCESS);
1366
1367 cleanup_zonestr:
1368	isc_mem_free(mctx, sdb->zone);
1369 cleanup_origin:
1370	dns_name_free(&sdb->common.origin, mctx);
1371 cleanup_lock:
1372	isc_mutex_destroy(&sdb->lock);
1373	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1374	isc_mem_detach(&mctx);
1375
1376	return (result);
1377}
1378
1379
1380/*
1381 * Rdataset Methods
1382 */
1383
1384static void
1385disassociate(dns_rdataset_t *rdataset) {
1386	dns_dbnode_t *node = rdataset->private5;
1387	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1388	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1389
1390	detachnode(db, &node);
1391	isc__rdatalist_disassociate(rdataset);
1392}
1393
1394static void
1395rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1396	dns_dbnode_t *node = source->private5;
1397	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1398	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1399	dns_dbnode_t *tempdb = NULL;
1400
1401	isc__rdatalist_clone(source, target);
1402	attachnode(db, node, &tempdb);
1403	source->private5 = tempdb;
1404}
1405
1406static dns_rdatasetmethods_t sdb_rdataset_methods = {
1407	disassociate,
1408	isc__rdatalist_first,
1409	isc__rdatalist_next,
1410	isc__rdatalist_current,
1411	rdataset_clone,
1412	isc__rdatalist_count,
1413	isc__rdatalist_addnoqname,
1414	isc__rdatalist_getnoqname,
1415	NULL, /* addclosest */
1416	NULL, /* getclosest */
1417	NULL, /* settrust */
1418	NULL, /* expire */
1419	NULL, /* clearprefetch */
1420	NULL, /* setownercase */
1421	NULL, /* getownercase */
1422	NULL  /* addglue */
1423};
1424
1425static void
1426list_tordataset(dns_rdatalist_t *rdatalist,
1427		dns_db_t *db, dns_dbnode_t *node,
1428		dns_rdataset_t *rdataset)
1429{
1430	/*
1431	 * The sdb rdataset is an rdatalist with some additions.
1432	 *	- private1 & private2 are used by the rdatalist.
1433	 *	- private3 & private 4 are unused.
1434	 *	- private5 is the node.
1435	 */
1436
1437	/* This should never fail. */
1438	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1439		      ISC_R_SUCCESS);
1440
1441	rdataset->methods = &sdb_rdataset_methods;
1442	dns_db_attachnode(db, node, &rdataset->private5);
1443}
1444
1445/*
1446 * Database Iterator Methods
1447 */
1448static void
1449dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1450	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1451	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1452
1453	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1454		dns_sdbnode_t *node;
1455		node = ISC_LIST_HEAD(sdbiter->nodelist);
1456		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1457		destroynode(node);
1458	}
1459
1460	dns_db_detach(&sdbiter->common.db);
1461	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1462
1463	*iteratorp = NULL;
1464}
1465
1466static isc_result_t
1467dbiterator_first(dns_dbiterator_t *iterator) {
1468	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1469
1470	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1471	if (sdbiter->current == NULL)
1472		return (ISC_R_NOMORE);
1473	else
1474		return (ISC_R_SUCCESS);
1475}
1476
1477static isc_result_t
1478dbiterator_last(dns_dbiterator_t *iterator) {
1479	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1480
1481	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1482	if (sdbiter->current == NULL)
1483		return (ISC_R_NOMORE);
1484	else
1485		return (ISC_R_SUCCESS);
1486}
1487
1488static isc_result_t
1489dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name) {
1490	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1491
1492	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1493	while (sdbiter->current != NULL) {
1494		if (dns_name_equal(sdbiter->current->name, name))
1495			return (ISC_R_SUCCESS);
1496		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1497	}
1498	return (ISC_R_NOTFOUND);
1499}
1500
1501static isc_result_t
1502dbiterator_prev(dns_dbiterator_t *iterator) {
1503	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1504
1505	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1506	if (sdbiter->current == NULL)
1507		return (ISC_R_NOMORE);
1508	else
1509		return (ISC_R_SUCCESS);
1510}
1511
1512static isc_result_t
1513dbiterator_next(dns_dbiterator_t *iterator) {
1514	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1515
1516	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1517	if (sdbiter->current == NULL)
1518		return (ISC_R_NOMORE);
1519	else
1520		return (ISC_R_SUCCESS);
1521}
1522
1523static isc_result_t
1524dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1525		   dns_name_t *name)
1526{
1527	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1528
1529	attachnode(iterator->db, sdbiter->current, nodep);
1530	if (name != NULL)
1531		return (dns_name_copy(sdbiter->current->name, name, NULL));
1532	return (ISC_R_SUCCESS);
1533}
1534
1535static isc_result_t
1536dbiterator_pause(dns_dbiterator_t *iterator) {
1537	UNUSED(iterator);
1538	return (ISC_R_SUCCESS);
1539}
1540
1541static isc_result_t
1542dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1543	UNUSED(iterator);
1544	return (dns_name_copy(dns_rootname, name, NULL));
1545}
1546
1547/*
1548 * Rdataset Iterator Methods
1549 */
1550
1551static void
1552rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1553	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1554	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1555	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1556		    sizeof(sdb_rdatasetiter_t));
1557	*iteratorp = NULL;
1558}
1559
1560static isc_result_t
1561rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1562	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1563	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1564
1565	if (ISC_LIST_EMPTY(sdbnode->lists))
1566		return (ISC_R_NOMORE);
1567	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1568	return (ISC_R_SUCCESS);
1569}
1570
1571static isc_result_t
1572rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1573	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1574
1575	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1576	if (sdbiterator->current == NULL)
1577		return (ISC_R_NOMORE);
1578	else
1579		return (ISC_R_SUCCESS);
1580}
1581
1582static void
1583rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1584	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1585
1586	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1587			rdataset);
1588}
1589