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