ecdb.c revision 224090
1/*
2 * Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: ecdb.c,v 1.8 2011-01-14 00:51:43 tbox Exp $ */
18
19#include "config.h"
20
21#include <isc/result.h>
22#include <isc/util.h>
23#include <isc/mutex.h>
24#include <isc/mem.h>
25
26#include <dns/db.h>
27#include <dns/ecdb.h>
28#include <dns/rdata.h>
29#include <dns/rdataset.h>
30#include <dns/rdatasetiter.h>
31#include <dns/rdataslab.h>
32
33#define ECDB_MAGIC		ISC_MAGIC('E', 'C', 'D', 'B')
34#define VALID_ECDB(db)		((db) != NULL && \
35				 (db)->common.impmagic == ECDB_MAGIC)
36
37#define ECDBNODE_MAGIC		ISC_MAGIC('E', 'C', 'D', 'N')
38#define VALID_ECDBNODE(ecdbn)	ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
39
40#if DNS_RDATASET_FIXED
41#error "Fixed rdataset isn't supported in this implementation"
42#endif
43
44/*%
45 * The 'ephemeral' cache DB (ecdb) implementation.  An ecdb just provides
46 * temporary storage for ongoing name resolution with the common DB interfaces.
47 * It actually doesn't cache anything.  The implementation expects any stored
48 * data is released within a short period, and does not care about the
49 * scalability in terms of the number of nodes.
50 */
51
52typedef struct dns_ecdb {
53	/* Unlocked */
54	dns_db_t			common;
55	isc_mutex_t			lock;
56
57	/* Locked */
58	unsigned int			references;
59	ISC_LIST(struct dns_ecdbnode)	nodes;
60} dns_ecdb_t;
61
62typedef struct dns_ecdbnode {
63	/* Unlocked */
64	unsigned int			magic;
65	isc_mutex_t			lock;
66	dns_ecdb_t			*ecdb;
67	dns_name_t			name;
68	ISC_LINK(struct dns_ecdbnode)	link;
69
70	/* Locked */
71	ISC_LIST(struct rdatasetheader)	rdatasets;
72	unsigned int			references;
73} dns_ecdbnode_t;
74
75typedef struct rdatasetheader {
76	dns_rdatatype_t			type;
77	dns_ttl_t			ttl;
78	dns_trust_t			trust;
79	dns_rdatatype_t			covers;
80	unsigned int			attributes;
81
82	ISC_LINK(struct rdatasetheader)	link;
83} rdatasetheader_t;
84
85/* Copied from rbtdb.c */
86#define RDATASET_ATTR_NXDOMAIN		0x0010
87#define NXDOMAIN(header) \
88	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
89
90static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
91				    dns_dbtype_t type,
92				    dns_rdataclass_t rdclass,
93				    unsigned int argc, char *argv[],
94				    void *driverarg, dns_db_t **dbp);
95
96static void rdataset_disassociate(dns_rdataset_t *rdataset);
97static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
98static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
99static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
100static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
101static unsigned int rdataset_count(dns_rdataset_t *rdataset);
102static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
103
104static dns_rdatasetmethods_t rdataset_methods = {
105	rdataset_disassociate,
106	rdataset_first,
107	rdataset_next,
108	rdataset_current,
109	rdataset_clone,
110	rdataset_count,
111	NULL,			/* addnoqname */
112	NULL,			/* getnoqname */
113	NULL,			/* addclosest */
114	NULL,			/* getclosest */
115	NULL,			/* getadditional */
116	NULL,			/* setadditional */
117	NULL,			/* putadditional */
118	rdataset_settrust,	/* settrust */
119	NULL			/* expire */
120};
121
122typedef struct ecdb_rdatasetiter {
123	dns_rdatasetiter_t		common;
124	rdatasetheader_t	       *current;
125} ecdb_rdatasetiter_t;
126
127static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
128static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
129static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
130static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
131					     dns_rdataset_t *rdataset);
132
133static dns_rdatasetitermethods_t rdatasetiter_methods = {
134	rdatasetiter_destroy,
135	rdatasetiter_first,
136	rdatasetiter_next,
137	rdatasetiter_current
138};
139
140isc_result_t
141dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
142	REQUIRE(mctx != NULL);
143	REQUIRE(dbimp != NULL && *dbimp == NULL);
144
145	return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
146}
147
148void
149dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
150	REQUIRE(dbimp != NULL && *dbimp != NULL);
151
152	dns_db_unregister(dbimp);
153}
154
155/*%
156 * DB routines
157 */
158
159static void
160attach(dns_db_t *source, dns_db_t **targetp) {
161	dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
162
163	REQUIRE(VALID_ECDB(ecdb));
164	REQUIRE(targetp != NULL && *targetp == NULL);
165
166	LOCK(&ecdb->lock);
167	ecdb->references++;
168	UNLOCK(&ecdb->lock);
169
170	*targetp = source;
171}
172
173static void
174destroy_ecdb(dns_ecdb_t **ecdbp) {
175	dns_ecdb_t *ecdb = *ecdbp;
176	isc_mem_t *mctx = ecdb->common.mctx;
177
178	if (dns_name_dynamic(&ecdb->common.origin))
179		dns_name_free(&ecdb->common.origin, mctx);
180
181	DESTROYLOCK(&ecdb->lock);
182
183	ecdb->common.impmagic = 0;
184	ecdb->common.magic = 0;
185
186	isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
187
188	*ecdbp = NULL;
189}
190
191static void
192detach(dns_db_t **dbp) {
193	dns_ecdb_t *ecdb;
194	isc_boolean_t need_destroy = ISC_FALSE;
195
196	REQUIRE(dbp != NULL);
197	ecdb = (dns_ecdb_t *)*dbp;
198	REQUIRE(VALID_ECDB(ecdb));
199
200	LOCK(&ecdb->lock);
201	ecdb->references--;
202	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
203		need_destroy = ISC_TRUE;
204	UNLOCK(&ecdb->lock);
205
206	if (need_destroy)
207		destroy_ecdb(&ecdb);
208
209	*dbp = NULL;
210}
211
212static void
213attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
214	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
215	dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
216
217	REQUIRE(VALID_ECDB(ecdb));
218	REQUIRE(VALID_ECDBNODE(node));
219	REQUIRE(targetp != NULL && *targetp == NULL);
220
221	LOCK(&node->lock);
222	INSIST(node->references > 0);
223	node->references++;
224	INSIST(node->references != 0);		/* Catch overflow. */
225	UNLOCK(&node->lock);
226
227	*targetp = node;
228}
229
230static void
231destroynode(dns_ecdbnode_t *node) {
232	isc_mem_t *mctx;
233	dns_ecdb_t *ecdb = node->ecdb;
234	isc_boolean_t need_destroydb = ISC_FALSE;
235	rdatasetheader_t *header;
236
237	mctx = ecdb->common.mctx;
238
239	LOCK(&ecdb->lock);
240	ISC_LIST_UNLINK(ecdb->nodes, node, link);
241	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
242		need_destroydb = ISC_TRUE;
243	UNLOCK(&ecdb->lock);
244
245	dns_name_free(&node->name, mctx);
246
247	while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
248		unsigned int headersize;
249
250		ISC_LIST_UNLINK(node->rdatasets, header, link);
251		headersize =
252			dns_rdataslab_size((unsigned char *)header,
253					   sizeof(*header));
254		isc_mem_put(mctx, header, headersize);
255	}
256
257	DESTROYLOCK(&node->lock);
258
259	node->magic = 0;
260	isc_mem_put(mctx, node, sizeof(*node));
261
262	if (need_destroydb)
263		destroy_ecdb(&ecdb);
264}
265
266static void
267detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
268	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
269	dns_ecdbnode_t *node;
270	isc_boolean_t need_destroy = ISC_FALSE;
271
272	REQUIRE(VALID_ECDB(ecdb));
273	REQUIRE(nodep != NULL);
274	node = (dns_ecdbnode_t *)*nodep;
275	REQUIRE(VALID_ECDBNODE(node));
276
277	UNUSED(ecdb);		/* in case REQUIRE() is empty */
278
279	LOCK(&node->lock);
280	INSIST(node->references > 0);
281	node->references--;
282	if (node->references == 0)
283		need_destroy = ISC_TRUE;
284	UNLOCK(&node->lock);
285
286	if (need_destroy)
287		destroynode(node);
288
289	*nodep = NULL;
290}
291
292static isc_result_t
293find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
294    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
295    dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
296    dns_rdataset_t *sigrdataset)
297{
298	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
299
300	REQUIRE(VALID_ECDB(ecdb));
301
302	UNUSED(name);
303	UNUSED(version);
304	UNUSED(type);
305	UNUSED(options);
306	UNUSED(now);
307	UNUSED(nodep);
308	UNUSED(foundname);
309	UNUSED(rdataset);
310	UNUSED(sigrdataset);
311
312	return (ISC_R_NOTFOUND);
313}
314
315static isc_result_t
316findzonecut(dns_db_t *db, dns_name_t *name,
317	    unsigned int options, isc_stdtime_t now,
318	    dns_dbnode_t **nodep, dns_name_t *foundname,
319	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
320{
321	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
322
323	REQUIRE(VALID_ECDB(ecdb));
324
325	UNUSED(name);
326	UNUSED(options);
327	UNUSED(now);
328	UNUSED(nodep);
329	UNUSED(foundname);
330	UNUSED(rdataset);
331	UNUSED(sigrdataset);
332
333	return (ISC_R_NOTFOUND);
334}
335
336static isc_result_t
337findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
338	 dns_dbnode_t **nodep)
339{
340	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
341	isc_mem_t *mctx;
342	dns_ecdbnode_t *node;
343	isc_result_t result;
344
345	REQUIRE(VALID_ECDB(ecdb));
346	REQUIRE(nodep != NULL && *nodep == NULL);
347
348	UNUSED(name);
349
350	if (create != ISC_TRUE)	{
351		/* an 'ephemeral' node is never reused. */
352		return (ISC_R_NOTFOUND);
353	}
354
355	mctx = ecdb->common.mctx;
356	node = isc_mem_get(mctx, sizeof(*node));
357	if (node == NULL)
358		return (ISC_R_NOMEMORY);
359
360	result = isc_mutex_init(&node->lock);
361	if (result != ISC_R_SUCCESS) {
362		UNEXPECTED_ERROR(__FILE__, __LINE__,
363				 "isc_mutex_init() failed: %s",
364				 isc_result_totext(result));
365		isc_mem_put(mctx, node, sizeof(*node));
366		return (ISC_R_UNEXPECTED);
367	}
368
369	dns_name_init(&node->name, NULL);
370	result = dns_name_dup(name, mctx, &node->name);
371	if (result != ISC_R_SUCCESS) {
372		DESTROYLOCK(&node->lock);
373		isc_mem_put(mctx, node, sizeof(*node));
374		return (result);
375	}
376	node->ecdb= ecdb;
377	node->references = 1;
378	ISC_LIST_INIT(node->rdatasets);
379
380	ISC_LINK_INIT(node, link);
381
382	LOCK(&ecdb->lock);
383	ISC_LIST_APPEND(ecdb->nodes, node, link);
384	UNLOCK(&ecdb->lock);
385
386	node->magic = ECDBNODE_MAGIC;
387
388	*nodep = node;
389
390	return (ISC_R_SUCCESS);
391}
392
393static void
394bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
395	      rdatasetheader_t *header, dns_rdataset_t *rdataset)
396{
397	unsigned char *raw;
398
399	/*
400	 * Caller must be holding the node lock.
401	 */
402
403	REQUIRE(!dns_rdataset_isassociated(rdataset));
404
405	rdataset->methods = &rdataset_methods;
406	rdataset->rdclass = ecdb->common.rdclass;
407	rdataset->type = header->type;
408	rdataset->covers = header->covers;
409	rdataset->ttl = header->ttl;
410	rdataset->trust = header->trust;
411	if (NXDOMAIN(header))
412		rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
413
414	rdataset->private1 = ecdb;
415	rdataset->private2 = node;
416	raw = (unsigned char *)header + sizeof(*header);
417	rdataset->private3 = raw;
418	rdataset->count = 0;
419
420	/*
421	 * Reset iterator state.
422	 */
423	rdataset->privateuint4 = 0;
424	rdataset->private5 = NULL;
425
426	INSIST(node->references > 0);
427	node->references++;
428}
429
430static isc_result_t
431addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
432	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
433	    dns_rdataset_t *addedrdataset)
434{
435	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
436	isc_region_t r;
437	isc_result_t result = ISC_R_SUCCESS;
438	isc_mem_t *mctx;
439	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
440	rdatasetheader_t *header;
441
442	REQUIRE(VALID_ECDB(ecdb));
443	REQUIRE(VALID_ECDBNODE(ecdbnode));
444
445	UNUSED(version);
446	UNUSED(now);
447	UNUSED(options);
448
449	mctx = ecdb->common.mctx;
450
451	LOCK(&ecdbnode->lock);
452
453	/*
454	 * Sanity check: this implementation does not allow overriding an
455	 * existing rdataset of the same type.
456	 */
457	for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
458	     header = ISC_LIST_NEXT(header, link)) {
459		INSIST(header->type != rdataset->type ||
460		       header->covers != rdataset->covers);
461	}
462
463	result = dns_rdataslab_fromrdataset(rdataset, mctx,
464					    &r, sizeof(rdatasetheader_t));
465	if (result != ISC_R_SUCCESS)
466		goto unlock;
467
468	header = (rdatasetheader_t *)r.base;
469	header->type = rdataset->type;
470	header->ttl = rdataset->ttl;
471	header->trust = rdataset->trust;
472	header->covers = rdataset->covers;
473	header->attributes = 0;
474	if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
475		header->attributes |= RDATASET_ATTR_NXDOMAIN;
476	ISC_LINK_INIT(header, link);
477	ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
478
479	if (addedrdataset == NULL)
480		goto unlock;
481
482	bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
483
484 unlock:
485	UNLOCK(&ecdbnode->lock);
486
487	return (result);
488}
489
490static isc_result_t
491deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
492	       dns_rdatatype_t type, dns_rdatatype_t covers)
493{
494	UNUSED(db);
495	UNUSED(node);
496	UNUSED(version);
497	UNUSED(type);
498	UNUSED(covers);
499
500	return (ISC_R_NOTIMPLEMENTED);
501}
502
503static isc_result_t
504createiterator(dns_db_t *db, unsigned int options,
505	       dns_dbiterator_t **iteratorp)
506{
507	UNUSED(db);
508	UNUSED(options);
509	UNUSED(iteratorp);
510
511	return (ISC_R_NOTIMPLEMENTED);
512}
513
514static isc_result_t
515allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
516	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
517{
518	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
519	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
520	isc_mem_t *mctx;
521	ecdb_rdatasetiter_t *iterator;
522
523	REQUIRE(VALID_ECDB(ecdb));
524	REQUIRE(VALID_ECDBNODE(ecdbnode));
525
526	mctx = ecdb->common.mctx;
527
528	iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
529	if (iterator == NULL)
530		return (ISC_R_NOMEMORY);
531
532	iterator->common.magic = DNS_RDATASETITER_MAGIC;
533	iterator->common.methods = &rdatasetiter_methods;
534	iterator->common.db = db;
535	iterator->common.node = NULL;
536	attachnode(db, node, &iterator->common.node);
537	iterator->common.version = version;
538	iterator->common.now = now;
539
540	*iteratorp = (dns_rdatasetiter_t *)iterator;
541
542	return (ISC_R_SUCCESS);
543}
544
545static dns_dbmethods_t ecdb_methods = {
546	attach,
547	detach,
548	NULL,			/* beginload */
549	NULL,			/* endload */
550	NULL,			/* dump */
551	NULL,			/* currentversion */
552	NULL,			/* newversion */
553	NULL,			/* attachversion */
554	NULL,			/* closeversion */
555	findnode,
556	find,
557	findzonecut,
558	attachnode,
559	detachnode,
560	NULL,			/* expirenode */
561	NULL,			/* printnode */
562	createiterator,		/* createiterator */
563	NULL,			/* findrdataset */
564	allrdatasets,
565	addrdataset,
566	NULL,			/* subtractrdataset */
567	deleterdataset,
568	NULL,			/* issecure */
569	NULL,			/* nodecount */
570	NULL,			/* ispersistent */
571	NULL,			/* overmem */
572	NULL,			/* settask */
573	NULL,			/* getoriginnode */
574	NULL,			/* transfernode */
575	NULL,			/* getnsec3parameters */
576	NULL,			/* findnsec3node */
577	NULL,			/* setsigningtime */
578	NULL,			/* getsigningtime */
579	NULL,			/* resigned */
580	NULL,			/* isdnssec */
581	NULL,			/* getrrsetstats */
582	NULL,			/* rpz_enabled */
583	NULL			/* rpz_findips */
584};
585
586static isc_result_t
587dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
588		dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
589		void *driverarg, dns_db_t **dbp)
590{
591	dns_ecdb_t *ecdb;
592	isc_result_t result;
593
594	REQUIRE(mctx != NULL);
595	REQUIRE(origin == dns_rootname);
596	REQUIRE(type == dns_dbtype_cache);
597	REQUIRE(dbp != NULL && *dbp == NULL);
598
599	UNUSED(argc);
600	UNUSED(argv);
601	UNUSED(driverarg);
602
603	ecdb = isc_mem_get(mctx, sizeof(*ecdb));
604	if (ecdb == NULL)
605		return (ISC_R_NOMEMORY);
606
607	ecdb->common.attributes = DNS_DBATTR_CACHE;
608	ecdb->common.rdclass = rdclass;
609	ecdb->common.methods = &ecdb_methods;
610	dns_name_init(&ecdb->common.origin, NULL);
611	result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
612	if (result != ISC_R_SUCCESS) {
613		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
614		return (result);
615	}
616
617	result = isc_mutex_init(&ecdb->lock);
618	if (result != ISC_R_SUCCESS) {
619		UNEXPECTED_ERROR(__FILE__, __LINE__,
620				 "isc_mutex_init() failed: %s",
621				 isc_result_totext(result));
622		if (dns_name_dynamic(&ecdb->common.origin))
623			dns_name_free(&ecdb->common.origin, mctx);
624		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
625		return (ISC_R_UNEXPECTED);
626	}
627
628	ecdb->references = 1;
629	ISC_LIST_INIT(ecdb->nodes);
630
631	ecdb->common.mctx = NULL;
632	isc_mem_attach(mctx, &ecdb->common.mctx);
633	ecdb->common.impmagic = ECDB_MAGIC;
634	ecdb->common.magic = DNS_DB_MAGIC;
635
636	*dbp = (dns_db_t *)ecdb;
637
638	return (ISC_R_SUCCESS);
639}
640
641/*%
642 * Rdataset Methods
643 */
644
645static void
646rdataset_disassociate(dns_rdataset_t *rdataset) {
647	dns_db_t *db = rdataset->private1;
648	dns_dbnode_t *node = rdataset->private2;
649
650	dns_db_detachnode(db, &node);
651}
652
653static isc_result_t
654rdataset_first(dns_rdataset_t *rdataset) {
655	unsigned char *raw = rdataset->private3;
656	unsigned int count;
657
658	count = raw[0] * 256 + raw[1];
659	if (count == 0) {
660		rdataset->private5 = NULL;
661		return (ISC_R_NOMORE);
662	}
663	raw += 2;
664	/*
665	 * The privateuint4 field is the number of rdata beyond the cursor
666	 * position, so we decrement the total count by one before storing
667	 * it.
668	 */
669	count--;
670	rdataset->privateuint4 = count;
671	rdataset->private5 = raw;
672
673	return (ISC_R_SUCCESS);
674}
675
676static isc_result_t
677rdataset_next(dns_rdataset_t *rdataset) {
678	unsigned int count;
679	unsigned int length;
680	unsigned char *raw;
681
682	count = rdataset->privateuint4;
683	if (count == 0)
684		return (ISC_R_NOMORE);
685	count--;
686	rdataset->privateuint4 = count;
687	raw = rdataset->private5;
688	length = raw[0] * 256 + raw[1];
689	raw += length + 2;
690	rdataset->private5 = raw;
691
692	return (ISC_R_SUCCESS);
693}
694
695static void
696rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
697	unsigned char *raw = rdataset->private5;
698	isc_region_t r;
699	unsigned int length;
700	unsigned int flags = 0;
701
702	REQUIRE(raw != NULL);
703
704	length = raw[0] * 256 + raw[1];
705	raw += 2;
706	if (rdataset->type == dns_rdatatype_rrsig) {
707		if (*raw & DNS_RDATASLAB_OFFLINE)
708			flags |= DNS_RDATA_OFFLINE;
709		length--;
710		raw++;
711	}
712	r.length = length;
713	r.base = raw;
714	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
715	rdata->flags |= flags;
716}
717
718static void
719rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
720	dns_db_t *db = source->private1;
721	dns_dbnode_t *node = source->private2;
722	dns_dbnode_t *cloned_node = NULL;
723
724	attachnode(db, node, &cloned_node);
725	*target = *source;
726
727	/*
728	 * Reset iterator state.
729	 */
730	target->privateuint4 = 0;
731	target->private5 = NULL;
732}
733
734static unsigned int
735rdataset_count(dns_rdataset_t *rdataset) {
736	unsigned char *raw = rdataset->private3;
737	unsigned int count;
738
739	count = raw[0] * 256 + raw[1];
740
741	return (count);
742}
743
744static void
745rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
746	rdatasetheader_t *header = rdataset->private3;
747
748	header--;
749	header->trust = rdataset->trust = trust;
750}
751
752/*
753 * Rdataset Iterator Methods
754 */
755
756static void
757rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
758	ecdb_rdatasetiter_t *ecdbiterator;
759	isc_mem_t *mctx;
760
761	REQUIRE(iteratorp != NULL);
762	ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp;
763	REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common));
764
765	mctx = ecdbiterator->common.db->mctx;
766
767	ecdbiterator->common.magic = 0;
768
769	dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node);
770	isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t));
771
772	*iteratorp = NULL;
773}
774
775static isc_result_t
776rdatasetiter_first(dns_rdatasetiter_t *iterator) {
777	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
778	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
779
780	REQUIRE(DNS_RDATASETITER_VALID(iterator));
781
782	if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
783		return (ISC_R_NOMORE);
784	ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
785	return (ISC_R_SUCCESS);
786}
787
788static isc_result_t
789rdatasetiter_next(dns_rdatasetiter_t *iterator) {
790	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
791
792	REQUIRE(DNS_RDATASETITER_VALID(iterator));
793
794	ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
795	if (ecdbiterator->current == NULL)
796		return (ISC_R_NOMORE);
797	else
798		return (ISC_R_SUCCESS);
799}
800
801static void
802rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
803	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
804	dns_ecdb_t *ecdb;
805
806	ecdb = (dns_ecdb_t *)iterator->db;
807	REQUIRE(VALID_ECDB(ecdb));
808
809	bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);
810}
811