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