2 * Copyright (C) 2009-2011 Internet Systems Consortium, Inc. ("ISC")
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.
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.
17 /* $Id: ecdb.c,v 1.8 2011-01-14 00:51:43 tbox Exp $ */
21 #include <isc/result.h>
23 #include <isc/mutex.h>
28 #include <dns/rdata.h>
29 #include <dns/rdataset.h>
30 #include <dns/rdatasetiter.h>
31 #include <dns/rdataslab.h>
33 #define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B')
34 #define VALID_ECDB(db) ((db) != NULL && \
35 (db)->common.impmagic == ECDB_MAGIC)
37 #define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N')
38 #define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
40 #if DNS_RDATASET_FIXED
41 #error "Fixed rdataset isn't supported in this implementation"
45 * The 'ephemeral' cache DB (ecdb) implementation. An ecdb just provides
46 * temporary storage for ongoing name resolution with the common DB interfaces.
47 * It actually doesn't cache anything. The implementation expects any stored
48 * data is released within a short period, and does not care about the
49 * scalability in terms of the number of nodes.
52 typedef struct dns_ecdb {
58 unsigned int references;
59 ISC_LIST(struct dns_ecdbnode) nodes;
62 typedef struct dns_ecdbnode {
68 ISC_LINK(struct dns_ecdbnode) link;
71 ISC_LIST(struct rdatasetheader) rdatasets;
72 unsigned int references;
75 typedef struct rdatasetheader {
79 dns_rdatatype_t covers;
80 unsigned int attributes;
82 ISC_LINK(struct rdatasetheader) link;
85 /* Copied from rbtdb.c */
86 #define RDATASET_ATTR_NXDOMAIN 0x0010
87 #define NXDOMAIN(header) \
88 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
90 static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
92 dns_rdataclass_t rdclass,
93 unsigned int argc, char *argv[],
94 void *driverarg, dns_db_t **dbp);
96 static void rdataset_disassociate(dns_rdataset_t *rdataset);
97 static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
98 static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
99 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
100 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
101 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
102 static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
104 static dns_rdatasetmethods_t rdataset_methods = {
105 rdataset_disassociate,
111 NULL, /* addnoqname */
112 NULL, /* getnoqname */
113 NULL, /* addclosest */
114 NULL, /* getclosest */
115 NULL, /* getadditional */
116 NULL, /* setadditional */
117 NULL, /* putadditional */
118 rdataset_settrust, /* settrust */
122 typedef struct ecdb_rdatasetiter {
123 dns_rdatasetiter_t common;
124 rdatasetheader_t *current;
125 } ecdb_rdatasetiter_t;
127 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
128 static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
129 static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
130 static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
131 dns_rdataset_t *rdataset);
133 static dns_rdatasetitermethods_t rdatasetiter_methods = {
134 rdatasetiter_destroy,
141 dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
142 REQUIRE(mctx != NULL);
143 REQUIRE(dbimp != NULL && *dbimp == NULL);
145 return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
149 dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
150 REQUIRE(dbimp != NULL && *dbimp != NULL);
152 dns_db_unregister(dbimp);
160 attach(dns_db_t *source, dns_db_t **targetp) {
161 dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
163 REQUIRE(VALID_ECDB(ecdb));
164 REQUIRE(targetp != NULL && *targetp == NULL);
174 destroy_ecdb(dns_ecdb_t **ecdbp) {
175 dns_ecdb_t *ecdb = *ecdbp;
176 isc_mem_t *mctx = ecdb->common.mctx;
178 if (dns_name_dynamic(&ecdb->common.origin))
179 dns_name_free(&ecdb->common.origin, mctx);
181 DESTROYLOCK(&ecdb->lock);
183 ecdb->common.impmagic = 0;
184 ecdb->common.magic = 0;
186 isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
192 detach(dns_db_t **dbp) {
194 isc_boolean_t need_destroy = ISC_FALSE;
196 REQUIRE(dbp != NULL);
197 ecdb = (dns_ecdb_t *)*dbp;
198 REQUIRE(VALID_ECDB(ecdb));
202 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
203 need_destroy = ISC_TRUE;
213 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
214 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
215 dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
217 REQUIRE(VALID_ECDB(ecdb));
218 REQUIRE(VALID_ECDBNODE(node));
219 REQUIRE(targetp != NULL && *targetp == NULL);
222 INSIST(node->references > 0);
224 INSIST(node->references != 0); /* Catch overflow. */
231 destroynode(dns_ecdbnode_t *node) {
233 dns_ecdb_t *ecdb = node->ecdb;
234 isc_boolean_t need_destroydb = ISC_FALSE;
235 rdatasetheader_t *header;
237 mctx = ecdb->common.mctx;
240 ISC_LIST_UNLINK(ecdb->nodes, node, link);
241 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
242 need_destroydb = ISC_TRUE;
245 dns_name_free(&node->name, mctx);
247 while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
248 unsigned int headersize;
250 ISC_LIST_UNLINK(node->rdatasets, header, link);
252 dns_rdataslab_size((unsigned char *)header,
254 isc_mem_put(mctx, header, headersize);
257 DESTROYLOCK(&node->lock);
260 isc_mem_put(mctx, node, sizeof(*node));
267 detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
268 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
269 dns_ecdbnode_t *node;
270 isc_boolean_t need_destroy = ISC_FALSE;
272 REQUIRE(VALID_ECDB(ecdb));
273 REQUIRE(nodep != NULL);
274 node = (dns_ecdbnode_t *)*nodep;
275 REQUIRE(VALID_ECDBNODE(node));
277 UNUSED(ecdb); /* in case REQUIRE() is empty */
280 INSIST(node->references > 0);
282 if (node->references == 0)
283 need_destroy = ISC_TRUE;
293 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
294 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
295 dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
296 dns_rdataset_t *sigrdataset)
298 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
300 REQUIRE(VALID_ECDB(ecdb));
312 return (ISC_R_NOTFOUND);
316 findzonecut(dns_db_t *db, dns_name_t *name,
317 unsigned int options, isc_stdtime_t now,
318 dns_dbnode_t **nodep, dns_name_t *foundname,
319 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
321 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
323 REQUIRE(VALID_ECDB(ecdb));
333 return (ISC_R_NOTFOUND);
337 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
338 dns_dbnode_t **nodep)
340 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
342 dns_ecdbnode_t *node;
345 REQUIRE(VALID_ECDB(ecdb));
346 REQUIRE(nodep != NULL && *nodep == NULL);
350 if (create != ISC_TRUE) {
351 /* an 'ephemeral' node is never reused. */
352 return (ISC_R_NOTFOUND);
355 mctx = ecdb->common.mctx;
356 node = isc_mem_get(mctx, sizeof(*node));
358 return (ISC_R_NOMEMORY);
360 result = isc_mutex_init(&node->lock);
361 if (result != ISC_R_SUCCESS) {
362 UNEXPECTED_ERROR(__FILE__, __LINE__,
363 "isc_mutex_init() failed: %s",
364 isc_result_totext(result));
365 isc_mem_put(mctx, node, sizeof(*node));
366 return (ISC_R_UNEXPECTED);
369 dns_name_init(&node->name, NULL);
370 result = dns_name_dup(name, mctx, &node->name);
371 if (result != ISC_R_SUCCESS) {
372 DESTROYLOCK(&node->lock);
373 isc_mem_put(mctx, node, sizeof(*node));
377 node->references = 1;
378 ISC_LIST_INIT(node->rdatasets);
380 ISC_LINK_INIT(node, link);
383 ISC_LIST_APPEND(ecdb->nodes, node, link);
386 node->magic = ECDBNODE_MAGIC;
390 return (ISC_R_SUCCESS);
394 bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
395 rdatasetheader_t *header, dns_rdataset_t *rdataset)
400 * Caller must be holding the node lock.
403 REQUIRE(!dns_rdataset_isassociated(rdataset));
405 rdataset->methods = &rdataset_methods;
406 rdataset->rdclass = ecdb->common.rdclass;
407 rdataset->type = header->type;
408 rdataset->covers = header->covers;
409 rdataset->ttl = header->ttl;
410 rdataset->trust = header->trust;
411 if (NXDOMAIN(header))
412 rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
414 rdataset->private1 = ecdb;
415 rdataset->private2 = node;
416 raw = (unsigned char *)header + sizeof(*header);
417 rdataset->private3 = raw;
421 * Reset iterator state.
423 rdataset->privateuint4 = 0;
424 rdataset->private5 = NULL;
426 INSIST(node->references > 0);
431 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
432 isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
433 dns_rdataset_t *addedrdataset)
435 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
437 isc_result_t result = ISC_R_SUCCESS;
439 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
440 rdatasetheader_t *header;
442 REQUIRE(VALID_ECDB(ecdb));
443 REQUIRE(VALID_ECDBNODE(ecdbnode));
449 mctx = ecdb->common.mctx;
451 LOCK(&ecdbnode->lock);
454 * Sanity check: this implementation does not allow overriding an
455 * existing rdataset of the same type.
457 for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
458 header = ISC_LIST_NEXT(header, link)) {
459 INSIST(header->type != rdataset->type ||
460 header->covers != rdataset->covers);
463 result = dns_rdataslab_fromrdataset(rdataset, mctx,
464 &r, sizeof(rdatasetheader_t));
465 if (result != ISC_R_SUCCESS)
468 header = (rdatasetheader_t *)r.base;
469 header->type = rdataset->type;
470 header->ttl = rdataset->ttl;
471 header->trust = rdataset->trust;
472 header->covers = rdataset->covers;
473 header->attributes = 0;
474 if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
475 header->attributes |= RDATASET_ATTR_NXDOMAIN;
476 ISC_LINK_INIT(header, link);
477 ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
479 if (addedrdataset == NULL)
482 bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
485 UNLOCK(&ecdbnode->lock);
491 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
492 dns_rdatatype_t type, dns_rdatatype_t covers)
500 return (ISC_R_NOTIMPLEMENTED);
504 createiterator(dns_db_t *db, unsigned int options,
505 dns_dbiterator_t **iteratorp)
511 return (ISC_R_NOTIMPLEMENTED);
515 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
516 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
518 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
519 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
521 ecdb_rdatasetiter_t *iterator;
523 REQUIRE(VALID_ECDB(ecdb));
524 REQUIRE(VALID_ECDBNODE(ecdbnode));
526 mctx = ecdb->common.mctx;
528 iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
529 if (iterator == NULL)
530 return (ISC_R_NOMEMORY);
532 iterator->common.magic = DNS_RDATASETITER_MAGIC;
533 iterator->common.methods = &rdatasetiter_methods;
534 iterator->common.db = db;
535 iterator->common.node = NULL;
536 attachnode(db, node, &iterator->common.node);
537 iterator->common.version = version;
538 iterator->common.now = now;
540 *iteratorp = (dns_rdatasetiter_t *)iterator;
542 return (ISC_R_SUCCESS);
545 static dns_dbmethods_t ecdb_methods = {
548 NULL, /* beginload */
551 NULL, /* currentversion */
552 NULL, /* newversion */
553 NULL, /* attachversion */
554 NULL, /* closeversion */
560 NULL, /* expirenode */
561 NULL, /* printnode */
562 createiterator, /* createiterator */
563 NULL, /* findrdataset */
566 NULL, /* subtractrdataset */
569 NULL, /* nodecount */
570 NULL, /* ispersistent */
573 NULL, /* getoriginnode */
574 NULL, /* transfernode */
575 NULL, /* getnsec3parameters */
576 NULL, /* findnsec3node */
577 NULL, /* setsigningtime */
578 NULL, /* getsigningtime */
581 NULL, /* getrrsetstats */
582 NULL, /* rpz_enabled */
583 NULL /* rpz_findips */
587 dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
588 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
589 void *driverarg, dns_db_t **dbp)
594 REQUIRE(mctx != NULL);
595 REQUIRE(origin == dns_rootname);
596 REQUIRE(type == dns_dbtype_cache);
597 REQUIRE(dbp != NULL && *dbp == NULL);
603 ecdb = isc_mem_get(mctx, sizeof(*ecdb));
605 return (ISC_R_NOMEMORY);
607 ecdb->common.attributes = DNS_DBATTR_CACHE;
608 ecdb->common.rdclass = rdclass;
609 ecdb->common.methods = &ecdb_methods;
610 dns_name_init(&ecdb->common.origin, NULL);
611 result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
612 if (result != ISC_R_SUCCESS) {
613 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
617 result = isc_mutex_init(&ecdb->lock);
618 if (result != ISC_R_SUCCESS) {
619 UNEXPECTED_ERROR(__FILE__, __LINE__,
620 "isc_mutex_init() failed: %s",
621 isc_result_totext(result));
622 if (dns_name_dynamic(&ecdb->common.origin))
623 dns_name_free(&ecdb->common.origin, mctx);
624 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
625 return (ISC_R_UNEXPECTED);
628 ecdb->references = 1;
629 ISC_LIST_INIT(ecdb->nodes);
631 ecdb->common.mctx = NULL;
632 isc_mem_attach(mctx, &ecdb->common.mctx);
633 ecdb->common.impmagic = ECDB_MAGIC;
634 ecdb->common.magic = DNS_DB_MAGIC;
636 *dbp = (dns_db_t *)ecdb;
638 return (ISC_R_SUCCESS);
646 rdataset_disassociate(dns_rdataset_t *rdataset) {
647 dns_db_t *db = rdataset->private1;
648 dns_dbnode_t *node = rdataset->private2;
650 dns_db_detachnode(db, &node);
654 rdataset_first(dns_rdataset_t *rdataset) {
655 unsigned char *raw = rdataset->private3;
658 count = raw[0] * 256 + raw[1];
660 rdataset->private5 = NULL;
661 return (ISC_R_NOMORE);
665 * The privateuint4 field is the number of rdata beyond the cursor
666 * position, so we decrement the total count by one before storing
670 rdataset->privateuint4 = count;
671 rdataset->private5 = raw;
673 return (ISC_R_SUCCESS);
677 rdataset_next(dns_rdataset_t *rdataset) {
682 count = rdataset->privateuint4;
684 return (ISC_R_NOMORE);
686 rdataset->privateuint4 = count;
687 raw = rdataset->private5;
688 length = raw[0] * 256 + raw[1];
690 rdataset->private5 = raw;
692 return (ISC_R_SUCCESS);
696 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
697 unsigned char *raw = rdataset->private5;
700 unsigned int flags = 0;
702 REQUIRE(raw != NULL);
704 length = raw[0] * 256 + raw[1];
706 if (rdataset->type == dns_rdatatype_rrsig) {
707 if (*raw & DNS_RDATASLAB_OFFLINE)
708 flags |= DNS_RDATA_OFFLINE;
714 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
715 rdata->flags |= flags;
719 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
720 dns_db_t *db = source->private1;
721 dns_dbnode_t *node = source->private2;
722 dns_dbnode_t *cloned_node = NULL;
724 attachnode(db, node, &cloned_node);
728 * Reset iterator state.
730 target->privateuint4 = 0;
731 target->private5 = NULL;
735 rdataset_count(dns_rdataset_t *rdataset) {
736 unsigned char *raw = rdataset->private3;
739 count = raw[0] * 256 + raw[1];
745 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
746 rdatasetheader_t *header = rdataset->private3;
749 header->trust = rdataset->trust = trust;
753 * Rdataset Iterator Methods
757 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
758 ecdb_rdatasetiter_t *ecdbiterator;
761 REQUIRE(iteratorp != NULL);
762 ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp;
763 REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common));
765 mctx = ecdbiterator->common.db->mctx;
767 ecdbiterator->common.magic = 0;
769 dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node);
770 isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t));
776 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
777 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
778 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
780 REQUIRE(DNS_RDATASETITER_VALID(iterator));
782 if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
783 return (ISC_R_NOMORE);
784 ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
785 return (ISC_R_SUCCESS);
789 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
790 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
792 REQUIRE(DNS_RDATASETITER_VALID(iterator));
794 ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
795 if (ecdbiterator->current == NULL)
796 return (ISC_R_NOMORE);
798 return (ISC_R_SUCCESS);
802 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
803 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
806 ecdb = (dns_ecdb_t *)iterator->db;
807 REQUIRE(VALID_ECDB(ecdb));
809 bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);