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