2 * Copyright (C) 2009-2011, 2013, 2014 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.
19 #include <isc/result.h>
21 #include <isc/mutex.h>
26 #include <dns/rdata.h>
27 #include <dns/rdataset.h>
28 #include <dns/rdatasetiter.h>
29 #include <dns/rdataslab.h>
31 #define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B')
32 #define VALID_ECDB(db) ((db) != NULL && \
33 (db)->common.impmagic == ECDB_MAGIC)
35 #define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N')
36 #define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
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.
46 typedef struct dns_ecdb {
52 unsigned int references;
53 ISC_LIST(struct dns_ecdbnode) nodes;
56 typedef struct dns_ecdbnode {
62 ISC_LINK(struct dns_ecdbnode) link;
65 ISC_LIST(struct rdatasetheader) rdatasets;
66 unsigned int references;
69 typedef struct rdatasetheader {
73 dns_rdatatype_t covers;
74 unsigned int attributes;
76 ISC_LINK(struct rdatasetheader) link;
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)
87 static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
89 dns_rdataclass_t rdclass,
90 unsigned int argc, char *argv[],
91 void *driverarg, dns_db_t **dbp);
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);
101 static dns_rdatasetmethods_t rdataset_methods = {
102 rdataset_disassociate,
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 */
119 typedef struct ecdb_rdatasetiter {
120 dns_rdatasetiter_t common;
121 rdatasetheader_t *current;
122 } ecdb_rdatasetiter_t;
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);
130 static dns_rdatasetitermethods_t rdatasetiter_methods = {
131 rdatasetiter_destroy,
138 dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
139 REQUIRE(mctx != NULL);
140 REQUIRE(dbimp != NULL && *dbimp == NULL);
142 return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
146 dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
147 REQUIRE(dbimp != NULL && *dbimp != NULL);
149 dns_db_unregister(dbimp);
157 attach(dns_db_t *source, dns_db_t **targetp) {
158 dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
160 REQUIRE(VALID_ECDB(ecdb));
161 REQUIRE(targetp != NULL && *targetp == NULL);
171 destroy_ecdb(dns_ecdb_t **ecdbp) {
172 dns_ecdb_t *ecdb = *ecdbp;
173 isc_mem_t *mctx = ecdb->common.mctx;
175 if (dns_name_dynamic(&ecdb->common.origin))
176 dns_name_free(&ecdb->common.origin, mctx);
178 DESTROYLOCK(&ecdb->lock);
180 ecdb->common.impmagic = 0;
181 ecdb->common.magic = 0;
183 isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
189 detach(dns_db_t **dbp) {
191 isc_boolean_t need_destroy = ISC_FALSE;
193 REQUIRE(dbp != NULL);
194 ecdb = (dns_ecdb_t *)*dbp;
195 REQUIRE(VALID_ECDB(ecdb));
199 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
200 need_destroy = ISC_TRUE;
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;
214 REQUIRE(VALID_ECDB(ecdb));
215 REQUIRE(VALID_ECDBNODE(node));
216 REQUIRE(targetp != NULL && *targetp == NULL);
219 INSIST(node->references > 0);
221 INSIST(node->references != 0); /* Catch overflow. */
228 destroynode(dns_ecdbnode_t *node) {
230 dns_ecdb_t *ecdb = node->ecdb;
231 isc_boolean_t need_destroydb = ISC_FALSE;
232 rdatasetheader_t *header;
234 mctx = ecdb->common.mctx;
237 ISC_LIST_UNLINK(ecdb->nodes, node, link);
238 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
239 need_destroydb = ISC_TRUE;
242 dns_name_free(&node->name, mctx);
244 while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
245 unsigned int headersize;
247 ISC_LIST_UNLINK(node->rdatasets, header, link);
249 dns_rdataslab_size((unsigned char *)header,
251 isc_mem_put(mctx, header, headersize);
254 DESTROYLOCK(&node->lock);
257 isc_mem_put(mctx, node, sizeof(*node));
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;
269 REQUIRE(VALID_ECDB(ecdb));
270 REQUIRE(nodep != NULL);
271 node = (dns_ecdbnode_t *)*nodep;
272 REQUIRE(VALID_ECDBNODE(node));
274 UNUSED(ecdb); /* in case REQUIRE() is empty */
277 INSIST(node->references > 0);
279 if (node->references == 0)
280 need_destroy = ISC_TRUE;
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)
295 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
297 REQUIRE(VALID_ECDB(ecdb));
309 return (ISC_R_NOTFOUND);
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)
318 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
320 REQUIRE(VALID_ECDB(ecdb));
330 return (ISC_R_NOTFOUND);
334 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
335 dns_dbnode_t **nodep)
337 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
339 dns_ecdbnode_t *node;
342 REQUIRE(VALID_ECDB(ecdb));
343 REQUIRE(nodep != NULL && *nodep == NULL);
347 if (create != ISC_TRUE) {
348 /* an 'ephemeral' node is never reused. */
349 return (ISC_R_NOTFOUND);
352 mctx = ecdb->common.mctx;
353 node = isc_mem_get(mctx, sizeof(*node));
355 return (ISC_R_NOMEMORY);
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);
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));
374 node->references = 1;
375 ISC_LIST_INIT(node->rdatasets);
377 ISC_LINK_INIT(node, link);
380 ISC_LIST_APPEND(ecdb->nodes, node, link);
383 node->magic = ECDBNODE_MAGIC;
387 return (ISC_R_SUCCESS);
391 bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
392 rdatasetheader_t *header, dns_rdataset_t *rdataset)
397 * Caller must be holding the node lock.
400 REQUIRE(!dns_rdataset_isassociated(rdataset));
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;
413 rdataset->private1 = ecdb;
414 rdataset->private2 = node;
415 raw = (unsigned char *)header + sizeof(*header);
416 rdataset->private3 = raw;
420 * Reset iterator state.
422 rdataset->privateuint4 = 0;
423 rdataset->private5 = NULL;
425 INSIST(node->references > 0);
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)
434 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
436 isc_result_t result = ISC_R_SUCCESS;
438 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
439 rdatasetheader_t *header;
441 REQUIRE(VALID_ECDB(ecdb));
442 REQUIRE(VALID_ECDBNODE(ecdbnode));
448 mctx = ecdb->common.mctx;
450 LOCK(&ecdbnode->lock);
453 * Sanity check: this implementation does not allow overriding an
454 * existing rdataset of the same type.
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);
462 result = dns_rdataslab_fromrdataset(rdataset, mctx,
463 &r, sizeof(rdatasetheader_t));
464 if (result != ISC_R_SUCCESS)
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);
480 if (addedrdataset == NULL)
483 bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
486 UNLOCK(&ecdbnode->lock);
492 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
493 dns_rdatatype_t type, dns_rdatatype_t covers)
501 return (ISC_R_NOTIMPLEMENTED);
505 createiterator(dns_db_t *db, unsigned int options,
506 dns_dbiterator_t **iteratorp)
512 return (ISC_R_NOTIMPLEMENTED);
516 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
517 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
519 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
520 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
522 ecdb_rdatasetiter_t *iterator;
524 REQUIRE(VALID_ECDB(ecdb));
525 REQUIRE(VALID_ECDBNODE(ecdbnode));
527 mctx = ecdb->common.mctx;
529 iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
530 if (iterator == NULL)
531 return (ISC_R_NOMEMORY);
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;
541 *iteratorp = (dns_rdatasetiter_t *)iterator;
543 return (ISC_R_SUCCESS);
546 static dns_dbmethods_t ecdb_methods = {
549 NULL, /* beginload */
552 NULL, /* currentversion */
553 NULL, /* newversion */
554 NULL, /* attachversion */
555 NULL, /* closeversion */
561 NULL, /* expirenode */
562 NULL, /* printnode */
563 createiterator, /* createiterator */
564 NULL, /* findrdataset */
567 NULL, /* subtractrdataset */
570 NULL, /* nodecount */
571 NULL, /* ispersistent */
574 NULL, /* getoriginnode */
575 NULL, /* transfernode */
576 NULL, /* getnsec3parameters */
577 NULL, /* findnsec3node */
578 NULL, /* setsigningtime */
579 NULL, /* getsigningtime */
582 NULL, /* getrrsetstats */
583 NULL, /* rpz_enabled */
584 NULL, /* rpz_findips */
585 NULL, /* findnodeext */
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)
597 REQUIRE(mctx != NULL);
598 REQUIRE(origin == dns_rootname);
599 REQUIRE(type == dns_dbtype_cache);
600 REQUIRE(dbp != NULL && *dbp == NULL);
606 ecdb = isc_mem_get(mctx, sizeof(*ecdb));
608 return (ISC_R_NOMEMORY);
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));
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);
631 ecdb->references = 1;
632 ISC_LIST_INIT(ecdb->nodes);
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;
639 *dbp = (dns_db_t *)ecdb;
641 return (ISC_R_SUCCESS);
649 rdataset_disassociate(dns_rdataset_t *rdataset) {
650 dns_db_t *db = rdataset->private1;
651 dns_dbnode_t *node = rdataset->private2;
653 dns_db_detachnode(db, &node);
657 rdataset_first(dns_rdataset_t *rdataset) {
658 unsigned char *raw = rdataset->private3;
661 count = raw[0] * 256 + raw[1];
663 rdataset->private5 = NULL;
664 return (ISC_R_NOMORE);
666 #if DNS_RDATASET_FIXED
667 raw += 2 + (4 * count);
672 * The privateuint4 field is the number of rdata beyond the cursor
673 * position, so we decrement the total count by one before storing
677 rdataset->privateuint4 = count;
678 rdataset->private5 = raw;
680 return (ISC_R_SUCCESS);
684 rdataset_next(dns_rdataset_t *rdataset) {
689 count = rdataset->privateuint4;
691 return (ISC_R_NOMORE);
693 rdataset->privateuint4 = count;
694 raw = rdataset->private5;
695 length = raw[0] * 256 + raw[1];
696 #if DNS_RDATASET_FIXED
701 rdataset->private5 = raw;
703 return (ISC_R_SUCCESS);
707 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
708 unsigned char *raw = rdataset->private5;
711 unsigned int flags = 0;
713 REQUIRE(raw != NULL);
715 length = raw[0] * 256 + raw[1];
716 #if DNS_RDATASET_FIXED
721 if (rdataset->type == dns_rdatatype_rrsig) {
722 if (*raw & DNS_RDATASLAB_OFFLINE)
723 flags |= DNS_RDATA_OFFLINE;
729 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
730 rdata->flags |= flags;
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;
739 attachnode(db, node, &cloned_node);
743 * Reset iterator state.
745 target->privateuint4 = 0;
746 target->private5 = NULL;
750 rdataset_count(dns_rdataset_t *rdataset) {
751 unsigned char *raw = rdataset->private3;
754 count = raw[0] * 256 + raw[1];
760 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
761 rdatasetheader_t *header = rdataset->private3;
764 header->trust = rdataset->trust = trust;
768 * Rdataset Iterator Methods
772 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
775 dns_rdatasetiter_t *rdatasetiterator;
776 ecdb_rdatasetiter_t *ecdbiterator;
779 REQUIRE(iteratorp != NULL);
780 REQUIRE(DNS_RDATASETITER_VALID(*iteratorp));
782 u.rdatasetiterator = *iteratorp;
784 mctx = u.ecdbiterator->common.db->mctx;
785 u.ecdbiterator->common.magic = 0;
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));
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;
800 REQUIRE(DNS_RDATASETITER_VALID(iterator));
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);
809 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
810 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
812 REQUIRE(DNS_RDATASETITER_VALID(iterator));
814 ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
815 if (ecdbiterator->current == NULL)
816 return (ISC_R_NOMORE);
818 return (ISC_R_SUCCESS);
822 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
823 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
826 ecdb = (dns_ecdb_t *)iterator->db;
827 REQUIRE(VALID_ECDB(ecdb));
829 bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);