2 * Copyright (C) 2009-2011, 2013 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.10 2011/12/20 00:06:53 marka 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)
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.
48 typedef struct dns_ecdb {
54 unsigned int references;
55 ISC_LIST(struct dns_ecdbnode) nodes;
58 typedef struct dns_ecdbnode {
64 ISC_LINK(struct dns_ecdbnode) link;
67 ISC_LIST(struct rdatasetheader) rdatasets;
68 unsigned int references;
71 typedef struct rdatasetheader {
75 dns_rdatatype_t covers;
76 unsigned int attributes;
78 ISC_LINK(struct rdatasetheader) link;
81 /* Copied from rbtdb.c */
82 #define RDATASET_ATTR_NXDOMAIN 0x0010
83 #define RDATASET_ATTR_NEGATIVE 0x0100
84 #define NXDOMAIN(header) \
85 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
86 #define NEGATIVE(header) \
87 (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
89 static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
91 dns_rdataclass_t rdclass,
92 unsigned int argc, char *argv[],
93 void *driverarg, dns_db_t **dbp);
95 static void rdataset_disassociate(dns_rdataset_t *rdataset);
96 static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
97 static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
98 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
99 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
100 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
101 static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
103 static dns_rdatasetmethods_t rdataset_methods = {
104 rdataset_disassociate,
110 NULL, /* addnoqname */
111 NULL, /* getnoqname */
112 NULL, /* addclosest */
113 NULL, /* getclosest */
114 NULL, /* getadditional */
115 NULL, /* setadditional */
116 NULL, /* putadditional */
117 rdataset_settrust, /* settrust */
121 typedef struct ecdb_rdatasetiter {
122 dns_rdatasetiter_t common;
123 rdatasetheader_t *current;
124 } ecdb_rdatasetiter_t;
126 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
127 static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
128 static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
129 static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
130 dns_rdataset_t *rdataset);
132 static dns_rdatasetitermethods_t rdatasetiter_methods = {
133 rdatasetiter_destroy,
140 dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
141 REQUIRE(mctx != NULL);
142 REQUIRE(dbimp != NULL && *dbimp == NULL);
144 return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
148 dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
149 REQUIRE(dbimp != NULL && *dbimp != NULL);
151 dns_db_unregister(dbimp);
159 attach(dns_db_t *source, dns_db_t **targetp) {
160 dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
162 REQUIRE(VALID_ECDB(ecdb));
163 REQUIRE(targetp != NULL && *targetp == NULL);
173 destroy_ecdb(dns_ecdb_t **ecdbp) {
174 dns_ecdb_t *ecdb = *ecdbp;
175 isc_mem_t *mctx = ecdb->common.mctx;
177 if (dns_name_dynamic(&ecdb->common.origin))
178 dns_name_free(&ecdb->common.origin, mctx);
180 DESTROYLOCK(&ecdb->lock);
182 ecdb->common.impmagic = 0;
183 ecdb->common.magic = 0;
185 isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
191 detach(dns_db_t **dbp) {
193 isc_boolean_t need_destroy = ISC_FALSE;
195 REQUIRE(dbp != NULL);
196 ecdb = (dns_ecdb_t *)*dbp;
197 REQUIRE(VALID_ECDB(ecdb));
201 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
202 need_destroy = ISC_TRUE;
212 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
213 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
214 dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
216 REQUIRE(VALID_ECDB(ecdb));
217 REQUIRE(VALID_ECDBNODE(node));
218 REQUIRE(targetp != NULL && *targetp == NULL);
221 INSIST(node->references > 0);
223 INSIST(node->references != 0); /* Catch overflow. */
230 destroynode(dns_ecdbnode_t *node) {
232 dns_ecdb_t *ecdb = node->ecdb;
233 isc_boolean_t need_destroydb = ISC_FALSE;
234 rdatasetheader_t *header;
236 mctx = ecdb->common.mctx;
239 ISC_LIST_UNLINK(ecdb->nodes, node, link);
240 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
241 need_destroydb = ISC_TRUE;
244 dns_name_free(&node->name, mctx);
246 while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
247 unsigned int headersize;
249 ISC_LIST_UNLINK(node->rdatasets, header, link);
251 dns_rdataslab_size((unsigned char *)header,
253 isc_mem_put(mctx, header, headersize);
256 DESTROYLOCK(&node->lock);
259 isc_mem_put(mctx, node, sizeof(*node));
266 detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
267 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
268 dns_ecdbnode_t *node;
269 isc_boolean_t need_destroy = ISC_FALSE;
271 REQUIRE(VALID_ECDB(ecdb));
272 REQUIRE(nodep != NULL);
273 node = (dns_ecdbnode_t *)*nodep;
274 REQUIRE(VALID_ECDBNODE(node));
276 UNUSED(ecdb); /* in case REQUIRE() is empty */
279 INSIST(node->references > 0);
281 if (node->references == 0)
282 need_destroy = ISC_TRUE;
292 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
293 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
294 dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
295 dns_rdataset_t *sigrdataset)
297 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
299 REQUIRE(VALID_ECDB(ecdb));
311 return (ISC_R_NOTFOUND);
315 findzonecut(dns_db_t *db, dns_name_t *name,
316 unsigned int options, isc_stdtime_t now,
317 dns_dbnode_t **nodep, dns_name_t *foundname,
318 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
320 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
322 REQUIRE(VALID_ECDB(ecdb));
332 return (ISC_R_NOTFOUND);
336 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
337 dns_dbnode_t **nodep)
339 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
341 dns_ecdbnode_t *node;
344 REQUIRE(VALID_ECDB(ecdb));
345 REQUIRE(nodep != NULL && *nodep == NULL);
349 if (create != ISC_TRUE) {
350 /* an 'ephemeral' node is never reused. */
351 return (ISC_R_NOTFOUND);
354 mctx = ecdb->common.mctx;
355 node = isc_mem_get(mctx, sizeof(*node));
357 return (ISC_R_NOMEMORY);
359 result = isc_mutex_init(&node->lock);
360 if (result != ISC_R_SUCCESS) {
361 UNEXPECTED_ERROR(__FILE__, __LINE__,
362 "isc_mutex_init() failed: %s",
363 isc_result_totext(result));
364 isc_mem_put(mctx, node, sizeof(*node));
365 return (ISC_R_UNEXPECTED);
368 dns_name_init(&node->name, NULL);
369 result = dns_name_dup(name, mctx, &node->name);
370 if (result != ISC_R_SUCCESS) {
371 DESTROYLOCK(&node->lock);
372 isc_mem_put(mctx, node, sizeof(*node));
376 node->references = 1;
377 ISC_LIST_INIT(node->rdatasets);
379 ISC_LINK_INIT(node, link);
382 ISC_LIST_APPEND(ecdb->nodes, node, link);
385 node->magic = ECDBNODE_MAGIC;
389 return (ISC_R_SUCCESS);
393 bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
394 rdatasetheader_t *header, dns_rdataset_t *rdataset)
399 * Caller must be holding the node lock.
402 REQUIRE(!dns_rdataset_isassociated(rdataset));
404 rdataset->methods = &rdataset_methods;
405 rdataset->rdclass = ecdb->common.rdclass;
406 rdataset->type = header->type;
407 rdataset->covers = header->covers;
408 rdataset->ttl = header->ttl;
409 rdataset->trust = header->trust;
410 if (NXDOMAIN(header))
411 rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
412 if (NEGATIVE(header))
413 rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
415 rdataset->private1 = ecdb;
416 rdataset->private2 = node;
417 raw = (unsigned char *)header + sizeof(*header);
418 rdataset->private3 = raw;
422 * Reset iterator state.
424 rdataset->privateuint4 = 0;
425 rdataset->private5 = NULL;
427 INSIST(node->references > 0);
432 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
433 isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
434 dns_rdataset_t *addedrdataset)
436 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
438 isc_result_t result = ISC_R_SUCCESS;
440 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
441 rdatasetheader_t *header;
443 REQUIRE(VALID_ECDB(ecdb));
444 REQUIRE(VALID_ECDBNODE(ecdbnode));
450 mctx = ecdb->common.mctx;
452 LOCK(&ecdbnode->lock);
455 * Sanity check: this implementation does not allow overriding an
456 * existing rdataset of the same type.
458 for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
459 header = ISC_LIST_NEXT(header, link)) {
460 INSIST(header->type != rdataset->type ||
461 header->covers != rdataset->covers);
464 result = dns_rdataslab_fromrdataset(rdataset, mctx,
465 &r, sizeof(rdatasetheader_t));
466 if (result != ISC_R_SUCCESS)
469 header = (rdatasetheader_t *)r.base;
470 header->type = rdataset->type;
471 header->ttl = rdataset->ttl;
472 header->trust = rdataset->trust;
473 header->covers = rdataset->covers;
474 header->attributes = 0;
475 if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
476 header->attributes |= RDATASET_ATTR_NXDOMAIN;
477 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
478 header->attributes |= RDATASET_ATTR_NEGATIVE;
479 ISC_LINK_INIT(header, link);
480 ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
482 if (addedrdataset == NULL)
485 bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
488 UNLOCK(&ecdbnode->lock);
494 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
495 dns_rdatatype_t type, dns_rdatatype_t covers)
503 return (ISC_R_NOTIMPLEMENTED);
507 createiterator(dns_db_t *db, unsigned int options,
508 dns_dbiterator_t **iteratorp)
514 return (ISC_R_NOTIMPLEMENTED);
518 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
519 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
521 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
522 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
524 ecdb_rdatasetiter_t *iterator;
526 REQUIRE(VALID_ECDB(ecdb));
527 REQUIRE(VALID_ECDBNODE(ecdbnode));
529 mctx = ecdb->common.mctx;
531 iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
532 if (iterator == NULL)
533 return (ISC_R_NOMEMORY);
535 iterator->common.magic = DNS_RDATASETITER_MAGIC;
536 iterator->common.methods = &rdatasetiter_methods;
537 iterator->common.db = db;
538 iterator->common.node = NULL;
539 attachnode(db, node, &iterator->common.node);
540 iterator->common.version = version;
541 iterator->common.now = now;
543 *iteratorp = (dns_rdatasetiter_t *)iterator;
545 return (ISC_R_SUCCESS);
548 static dns_dbmethods_t ecdb_methods = {
551 NULL, /* beginload */
554 NULL, /* currentversion */
555 NULL, /* newversion */
556 NULL, /* attachversion */
557 NULL, /* closeversion */
563 NULL, /* expirenode */
564 NULL, /* printnode */
565 createiterator, /* createiterator */
566 NULL, /* findrdataset */
569 NULL, /* subtractrdataset */
572 NULL, /* nodecount */
573 NULL, /* ispersistent */
576 NULL, /* getoriginnode */
577 NULL, /* transfernode */
578 NULL, /* getnsec3parameters */
579 NULL, /* findnsec3node */
580 NULL, /* setsigningtime */
581 NULL, /* getsigningtime */
584 NULL, /* getrrsetstats */
585 NULL, /* rpz_enabled */
586 NULL, /* rpz_findips */
587 NULL, /* findnodeext */
592 dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
593 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
594 void *driverarg, dns_db_t **dbp)
599 REQUIRE(mctx != NULL);
600 REQUIRE(origin == dns_rootname);
601 REQUIRE(type == dns_dbtype_cache);
602 REQUIRE(dbp != NULL && *dbp == NULL);
608 ecdb = isc_mem_get(mctx, sizeof(*ecdb));
610 return (ISC_R_NOMEMORY);
612 ecdb->common.attributes = DNS_DBATTR_CACHE;
613 ecdb->common.rdclass = rdclass;
614 ecdb->common.methods = &ecdb_methods;
615 dns_name_init(&ecdb->common.origin, NULL);
616 result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
617 if (result != ISC_R_SUCCESS) {
618 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
622 result = isc_mutex_init(&ecdb->lock);
623 if (result != ISC_R_SUCCESS) {
624 UNEXPECTED_ERROR(__FILE__, __LINE__,
625 "isc_mutex_init() failed: %s",
626 isc_result_totext(result));
627 if (dns_name_dynamic(&ecdb->common.origin))
628 dns_name_free(&ecdb->common.origin, mctx);
629 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
630 return (ISC_R_UNEXPECTED);
633 ecdb->references = 1;
634 ISC_LIST_INIT(ecdb->nodes);
636 ecdb->common.mctx = NULL;
637 isc_mem_attach(mctx, &ecdb->common.mctx);
638 ecdb->common.impmagic = ECDB_MAGIC;
639 ecdb->common.magic = DNS_DB_MAGIC;
641 *dbp = (dns_db_t *)ecdb;
643 return (ISC_R_SUCCESS);
651 rdataset_disassociate(dns_rdataset_t *rdataset) {
652 dns_db_t *db = rdataset->private1;
653 dns_dbnode_t *node = rdataset->private2;
655 dns_db_detachnode(db, &node);
659 rdataset_first(dns_rdataset_t *rdataset) {
660 unsigned char *raw = rdataset->private3;
663 count = raw[0] * 256 + raw[1];
665 rdataset->private5 = NULL;
666 return (ISC_R_NOMORE);
668 #if DNS_RDATASET_FIXED
669 raw += 2 + (4 * count);
674 * The privateuint4 field is the number of rdata beyond the cursor
675 * position, so we decrement the total count by one before storing
679 rdataset->privateuint4 = count;
680 rdataset->private5 = raw;
682 return (ISC_R_SUCCESS);
686 rdataset_next(dns_rdataset_t *rdataset) {
691 count = rdataset->privateuint4;
693 return (ISC_R_NOMORE);
695 rdataset->privateuint4 = count;
696 raw = rdataset->private5;
697 length = raw[0] * 256 + raw[1];
698 #if DNS_RDATASET_FIXED
703 rdataset->private5 = raw;
705 return (ISC_R_SUCCESS);
709 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
710 unsigned char *raw = rdataset->private5;
713 unsigned int flags = 0;
715 REQUIRE(raw != NULL);
717 length = raw[0] * 256 + raw[1];
718 #if DNS_RDATASET_FIXED
723 if (rdataset->type == dns_rdatatype_rrsig) {
724 if (*raw & DNS_RDATASLAB_OFFLINE)
725 flags |= DNS_RDATA_OFFLINE;
731 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
732 rdata->flags |= flags;
736 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
737 dns_db_t *db = source->private1;
738 dns_dbnode_t *node = source->private2;
739 dns_dbnode_t *cloned_node = NULL;
741 attachnode(db, node, &cloned_node);
745 * Reset iterator state.
747 target->privateuint4 = 0;
748 target->private5 = NULL;
752 rdataset_count(dns_rdataset_t *rdataset) {
753 unsigned char *raw = rdataset->private3;
756 count = raw[0] * 256 + raw[1];
762 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
763 rdatasetheader_t *header = rdataset->private3;
766 header->trust = rdataset->trust = trust;
770 * Rdataset Iterator Methods
774 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
775 ecdb_rdatasetiter_t *ecdbiterator;
778 REQUIRE(iteratorp != NULL);
779 ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp;
780 REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common));
782 mctx = ecdbiterator->common.db->mctx;
784 ecdbiterator->common.magic = 0;
786 dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node);
787 isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t));
793 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
794 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
795 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
797 REQUIRE(DNS_RDATASETITER_VALID(iterator));
799 if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
800 return (ISC_R_NOMORE);
801 ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
802 return (ISC_R_SUCCESS);
806 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
807 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
809 REQUIRE(DNS_RDATASETITER_VALID(iterator));
811 ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
812 if (ecdbiterator->current == NULL)
813 return (ISC_R_NOMORE);
815 return (ISC_R_SUCCESS);
819 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
820 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
823 ecdb = (dns_ecdb_t *)iterator->db;
824 REQUIRE(VALID_ECDB(ecdb));
826 bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);