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