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