]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
autotrust work
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 13 Aug 2009 15:32:04 +0000 (15:32 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 13 Aug 2009 15:32:04 +0000 (15:32 +0000)
git-svn-id: file:///svn/unbound/trunk@1760 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
iterator/iter_utils.c
testcode/checklocks.c
testcode/unitanchor.c
validator/autotrust.c
validator/autotrust.h
validator/val_anchor.c
validator/val_anchor.h
validator/val_utils.c
validator/validator.c
validator/validator.h

index 4b3a01d9b32e9528d015efe0a3105bae61bdd249..793e530c90f95592254f3cd1e1ee09666b29eb94 100644 (file)
@@ -1,3 +1,6 @@
+13 August 2009: Wouter
+       - autotrust read anchor files. locked trust anchors.
+
 12 August 2009: Wouter
        - autotrust import work.
 
index 9ff4745467f2d86a68434854833ee0b84795353b..bb529759c9c7ec33819240ca551912f3dd90eefb 100644 (file)
@@ -476,13 +476,16 @@ int
 iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
         struct dns_msg* msg, uint16_t dclass)
 {
+       struct trust_anchor* a;
        /* information not available, !env->anchors can be common */
        if(!env || !env->anchors || !dp || !dp->name)
                return 0;
        /* a trust anchor exists with this name, RRSIGs expected */
-       if(anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
-               dclass))
+       if((a=anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
+               dclass))) {
+               lock_basic_unlock(&a->lock);
                return 1;
+       }
        /* see if DS rrset was given, in AUTH section */
        if(msg && msg->rep &&
                reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
index 520e6ddd16770bdbed6917c6e892f00ac2f9b98c..3ab9ebaf5955ca0b3b21d22128d5c2865190ef41 100644 (file)
@@ -87,6 +87,7 @@ static void lock_error(struct checked_lock* lock,
                (lock->type==check_lock_rwlock)?"rwlock": "badtype")), err);
        log_err("complete status display:");
        total_debug_info();
+       abort();
        fatal_exit("bailing out");
 }
 
index 59728446315272dc5a103c6361b9e5e0f49fa93f..ea090bc7e09dde727850e5d47201ee3041188ffc 100644 (file)
@@ -64,6 +64,7 @@ test_anchor_empty(struct val_anchors* a)
 static void
 test_anchor_one(ldns_buffer* buff, struct val_anchors* a)
 {
+       struct trust_anchor* ta;
        uint16_t c = LDNS_RR_CLASS_IN;
        unit_assert(anchor_store_str(a, buff, 
                "nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A"));
@@ -71,11 +72,19 @@ test_anchor_one(ldns_buffer* buff, struct val_anchors* a)
        unit_assert(anchors_lookup(a, (uint8_t*)"\003com\000", 5, c) == NULL);
        unit_assert(anchors_lookup(a, 
                (uint8_t*)"\007example\003com\000", 11, c) == NULL);
-       unit_assert(anchors_lookup(a, (uint8_t*)"\002nl\000", 4, c) != NULL);
-       unit_assert(anchors_lookup(a, 
-               (uint8_t*)"\004labs\002nl\000", 9, c) != NULL);
-       unit_assert(anchors_lookup(a, 
-               (uint8_t*)"\004fabs\002nl\000", 9, c) != NULL);
+
+       unit_assert((ta=anchors_lookup(a,
+               (uint8_t*)"\002nl\000", 4, c)) != NULL);
+       lock_basic_unlock(&ta->lock);
+
+       unit_assert((ta=anchors_lookup(a, 
+               (uint8_t*)"\004labs\002nl\000", 9, c)) != NULL);
+       lock_basic_unlock(&ta->lock);
+
+       unit_assert((ta=anchors_lookup(a, 
+               (uint8_t*)"\004fabs\002nl\000", 9, c)) != NULL);
+       lock_basic_unlock(&ta->lock);
+
        unit_assert(anchors_lookup(a, (uint8_t*)"\002oo\000", 4, c) == NULL);
 }
 
@@ -91,16 +100,23 @@ test_anchors(ldns_buffer* buff, struct val_anchors* a)
        unit_assert(anchors_lookup(a, (uint8_t*)"\003com\000", 5, c) == NULL);
        unit_assert(anchors_lookup(a, 
                (uint8_t*)"\007example\003com\000", 11, c) == NULL);
+
        unit_assert(ta = anchors_lookup(a, (uint8_t*)"\002nl\000", 4, c));
        unit_assert(query_dname_compare(ta->name, (uint8_t*)"\002nl\000")==0);
+       lock_basic_unlock(&ta->lock);
+
        unit_assert(ta = anchors_lookup(a, 
                (uint8_t*)"\004labs\002nl\000", 9, c));
        unit_assert(query_dname_compare(ta->name, 
                (uint8_t*)"\004labs\002nl\000") == 0);
+       lock_basic_unlock(&ta->lock);
+
        unit_assert(ta = anchors_lookup(a, 
                (uint8_t*)"\004fabs\002nl\000", 9, c));
        unit_assert(query_dname_compare(ta->name, 
                (uint8_t*)"\002nl\000") == 0);
+       lock_basic_unlock(&ta->lock);
+
        unit_assert(anchors_lookup(a, (uint8_t*)"\002oo\000", 4, c) == NULL);
 }
 
index d5593ccec2538a9eef487e73883b37f088586fd5..4cd4633337a4ead35ca613879fafeaf4ae91efdb 100644 (file)
 #include "config.h"
 #include "validator/autotrust.h"
 #include "validator/val_anchor.h"
+#include "util/data/dname.h"
 #include "util/log.h"
+#include "util/module.h"
 #include "util/net_help.h"
 
-/** max length of parse lines */
-#define MAXLEN 10240
-
 struct autr_global_data* autr_global_create(void)
 {
        struct autr_global_data* global;
@@ -104,31 +103,31 @@ position_in_string(char *str, const char* sub)
         }
         if (pos < 0)
                 return pos;
-        return pos + strlen(sub);
+        return pos + (int)strlen(sub);
 }
 
 /** 
  * Parse comments 
  * @param str: to parse
  * @param ta: trust key autotrust metadata
- * @param tp: trust anchor
  * @return false on failure.
  */
 static int
-parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
+parse_comments(char* str, struct autr_ta* ta)
 {
-        char* comment = (char*) malloc(sizeof(char)*MAXLEN);
+        int len = (int)strlen(str), pos = 0, timestamp = 0;
+        char* comment = (char*) malloc(sizeof(char)*len+1);
         char* comments = comment;
-        int len = strlen(str), pos = 0, timestamp = 0;
-        if (len >= MAXLEN) {
-               log_err("line too long");
+       if(!comment) {
+               log_err("malloc failure in parse");
                 return 0;
        }
+       /* skip over whitespace and data at start of line */
         while (*str != '\0' && *str != ';')
                 str++;
-        /* comments */
         if (*str == ';')
                 str++;
+        /* copy comments */
         while (*str != '\0')
         {
                 *comments = *str;
@@ -139,10 +138,6 @@ parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
 
         comments = comment;
 
-        if (!ta || !comments) {
-               log_err("malloc failure in parse");
-                return 0;
-       }
         /* read state */
         pos = position_in_string(comments, "state=");
         if (pos >= (int) strlen(comments))
@@ -152,10 +147,11 @@ parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
                 return 0;
         }
         if (pos <= 0)
-                ta->s = AUTR_STATE_START;
+                ta->s = AUTR_STATE_VALID;
         else
         {
                 int s = (int) comments[pos] - '0';
+               char* str = ldns_rdf2str(ldns_rr_owner(ta->rr));
 
                 switch(s)
                 {
@@ -168,10 +164,9 @@ parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
                                 ta->s = s;
                                 break;
                         default:
-                                log_nametypeclass(0, "warning: trust anchor "
-                                       "has undefined state, considered "
-                                       "NewKey", tp->name, 
-                                       LDNS_RR_TYPE_DNSKEY, tp->dclass);
+                               log_warn("trust anchor [%s, DNSKEY, id=%i] has "
+                                       "undefined state, considered NewKey",
+                                       str, ldns_calc_keytag(ta->rr));
                                 ta->s = AUTR_STATE_START;
                                 break;
                 }
@@ -191,7 +186,7 @@ parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
         else
         {
                 comments += pos;
-                ta->pending_count = atoi(comments);
+                ta->pending_count = (uint8_t)atoi(comments);
         }
 
         /* read last change */
@@ -209,12 +204,17 @@ parse_comments(char* str, struct autr_ta_data* ta, struct trust_anchor* tp)
         }
         if (pos < 0 || !timestamp)
         {
-                log_warn("trust anchor has no timestamp, considered NOW");
-                free(str);
-                ta->last_change = time(NULL);
+               /* Should we warn about this? It happens for key priming.
+               ldns_rdf* owner = ldns_rr_owner(ta->rr);
+               char* str = ldns_rdf2str(owner);
+               log_warn("trust anchor [%s, DNSKEY, id=%i] has no timestamp, "
+                       "considered NOW", str, ldns_calc_keytag(ta->rr));
+               free(str);
+               */
+               ta->last_change = (uint32_t)time(NULL);
         }
         else
-                ta->last_change = timestamp;
+                ta->last_change = (uint32_t)timestamp;
 
         free(comment);
         return 1;
@@ -236,80 +236,191 @@ str_contains_data(char* str, char comment)
 
 /** Get DNSKEY flags */
 static int
-ta_dnskey_flags(struct ta_key* ta)
+dnskey_flags(ldns_rr* rr)
 {
-       uint16_t f;
-       if(ta->type != LDNS_RR_TYPE_DNSKEY)
-               return 0;
-       if(ta->len < 2+2)
+       if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)
                return 0;
-       memmove(&f, ta->data+2, 2);
-       f = ntohs(f);
-       return f;
+       return (int)ldns_read_uint16(ldns_rdf_data(ldns_rr_dnskey_flags(rr)));
 }
 
 
 /** Check if KSK DNSKEY */
 static int
-rr_is_dnskey_sep(struct ta_key* ta)
+rr_is_dnskey_sep(ldns_rr* rr)
+{
+       return (dnskey_flags(rr)&DNSKEY_BIT_SEP);
+}
+
+/** create ta */
+static struct autr_ta*
+autr_ta_create(ldns_rr* rr)
+{
+       struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta));
+       if(!ta) {
+               ldns_rr_free(rr);
+               return NULL;
+       }
+       ta->rr = rr;
+       return ta;
+}
+
+/** create tp */
+static struct trust_anchor*
+autr_tp_create(struct val_anchors* anchors, ldns_rr* rr)
+{
+       ldns_rdf* own = ldns_rr_owner(rr);
+       struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp));
+       if(!tp) return NULL;
+       tp->name = memdup(ldns_rdf_data(own), ldns_rdf_size(own));
+       if(!tp->name) {
+               free(tp);
+               return NULL;
+       }
+       tp->namelen = ldns_rdf_size(own);
+       tp->namelabs = dname_count_labels(tp->name);
+       tp->node.key = tp;
+       tp->dclass = ldns_rr_get_class(rr);
+       tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr));
+       if(!tp->autr) {
+               free(tp->name);
+               free(tp);
+               return NULL;
+       }
+       tp->autr->pnode.key = tp;
+
+       lock_basic_lock(&anchors->lock);
+       (void)rbtree_insert(anchors->tree, &tp->node);
+       lock_basic_unlock(&anchors->lock);
+       lock_basic_init(&tp->lock);
+       lock_protect(&tp->lock, tp, sizeof(*tp));
+       lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
+       return tp;
+}
+
+void autr_point_delete(struct trust_anchor* tp)
+{
+       if(!tp)
+               return;
+       lock_unprotect(&tp->lock, tp);
+       lock_unprotect(&tp->lock, tp->autr);
+       lock_basic_destroy(&tp->lock);
+       free(tp->autr);
+       free(tp->name);
+       free(tp);
+}
+
+/** find or add a new trust point for autotrust */
+static struct trust_anchor*
+find_add_tp(struct val_anchors* anchors, ldns_rr* rr)
 {
-       return (ta_dnskey_flags(ta)&DNSKEY_BIT_SEP);
+       struct trust_anchor* tp;
+       ldns_rdf* own = ldns_rr_owner(rr);
+       tp = anchor_find(anchors, ldns_rdf_data(own), 
+               dname_count_labels(ldns_rdf_data(own)),
+               ldns_rdf_size(own), ldns_rr_get_class(rr));
+       if(tp) {
+               if(!tp->autr) {
+                       log_err("anchor cannot be with and without autotrust");
+                       lock_basic_unlock(&tp->lock);
+                       return NULL;
+               }
+               return tp;
+       }
+       tp = autr_tp_create(anchors, rr);
+       lock_basic_lock(&tp->lock);
+       return tp;
+}
+
+/** Add trust anchor from RR. */
+static struct autr_ta*
+add_trustanchor_frm_rr(struct val_anchors* anchors, ldns_rr* rr, 
+       struct trust_anchor** tp)
+{
+       struct autr_ta* ta = autr_ta_create(rr);
+       if(!ta) 
+               return NULL;
+       *tp = find_add_tp(anchors, rr);
+       /* add ta to tp */
+       ta->next = (*tp)->autr->keys;
+       (*tp)->autr->keys = ta;
+       lock_basic_unlock(&(*tp)->lock);
+       return ta;
 }
 
 /**
  * Add new trust anchor from a string in file.
  * @param anchors: all anchors
- * @param str: string with comments before the anchor, if any comments.
+ * @param str: string with anchor and comments, if any comments.
  * @param tp: trust point returned.
  * @return new key in trust point.
  */
-static struct ta_key*
+static struct autr_ta*
 add_trustanchor_frm_str(struct val_anchors* anchors, char* str, 
        struct trust_anchor** tp)
 {
-       if(!str_contains_data(str, ';'))
-               return NULL; /* empty line */
+        ldns_rr* rr;
+        struct autr_ta* ta = NULL;
+       ldns_status lstatus;
+        if (!str_contains_data(str, ';'))
+                return NULL; /* empty line */
+        if (LDNS_STATUS_OK !=
+                (lstatus = ldns_rr_new_frm_str(&rr, str, 0, NULL, NULL)))
+        {
+               log_err("ldns error while converting string to RR: %s",
+                       ldns_get_errorstr_by_id(lstatus));
+                return NULL;
+        }
+        ta = add_trustanchor_frm_rr(anchors, rr, tp);
+        return ta;
 }
 
 /** 
  * Load single anchor 
  * @param anchors: all points.
  * @param str: comments line
+ * @param fname: filename
  * @return false on failure.
  */
 static int
-load_trustanchor(struct val_anchors* anchors, char* str)
+load_trustanchor(struct val_anchors* anchors, char* str, const char* fname)
 {
-        int status_ok = 1;
-        struct ta_key* ta = NULL;
+        struct autr_ta* ta = NULL;
         struct trust_anchor* tp = NULL;
 
-        if (!str_contains_data(str, ';'))
-                return status_ok; /* empty lines allowed */
         ta = add_trustanchor_frm_str(anchors, str, &tp);
-        if (ta) {
-               status_ok = parse_comments(str, ta->autr, tp);
-               if (rr_is_dnskey_sep(ta)) {
-                       if (ta->autr->s == AUTR_STATE_VALID)
-                               tp->autr->valid ++;
-                       else if (ta->autr->s == AUTR_STATE_MISSING)
-                               tp->autr->missing ++;
+       if(!ta)
+               return 0;
+       lock_basic_lock(&tp->lock);
+       if(!parse_comments(str, ta)) {
+               lock_basic_unlock(&tp->lock);
+               return 0;
+       }
+       if (rr_is_dnskey_sep(ta->rr)) {
+               if (ta->s == AUTR_STATE_VALID)
+                       tp->autr->valid ++;
+               else if (ta->s == AUTR_STATE_MISSING)
+                       tp->autr->missing ++;
+       }
+       if(!tp->autr->file) {
+               /* TODO insert tp into probe tree */
+               tp->autr->file = strdup(fname);
+               if(!tp->autr->file) {
+                       lock_basic_unlock(&tp->lock);
+                       return 0;
                }
-        }
-        else
-                return 0;
-        return status_ok;
+       }
+       lock_basic_unlock(&tp->lock);
+        return 1;
 }
 
-int autr_read_file(struct val_anchors* anchors, ldns_buffer* parsebuf,
-       const char* nm)
+int autr_read_file(struct val_anchors* anchors, const char* nm)
 {
         /* the file descriptor */
         FILE* fd;
         /* keep track of line numbers */
         int line_nr = 0;
         /* single line */
-        char line[MAXLEN];
+        char line[10240];
 
         if (!(fd = fopen(nm, "r"))) {
                 log_err("unable to open %s for reading: %s", 
@@ -317,9 +428,13 @@ int autr_read_file(struct val_anchors* anchors, ldns_buffer* parsebuf,
                 return 0;
         }
         verbose(VERB_ALGO, "reading trust anchor file %s", nm);
-        while (fgets(line, MAXLEN, fd) != NULL) {
+       /* TODO: read line to see if special marker for revoked tp */
+       /* TODO: read next probe time (if in file, otherwise now+0-100s) */
+        while (fgets(line, (int)sizeof(line), fd) != NULL) {
                 line_nr++;
-                if (!load_trustanchor(anchors, line)) {
+               if (!str_contains_data(line, ';'))
+                       continue; /* empty lines allowed */
+                if (!load_trustanchor(anchors, line, nm)) {
                         log_err("failed to load trust anchor from %s "
                                "at line %i, skipping", nm, line_nr);
                         /* try to do the rest */
@@ -330,3 +445,19 @@ int autr_read_file(struct val_anchors* anchors, ldns_buffer* parsebuf,
        return 1;
 }
 
+void autr_write_file(struct trust_anchor* tp)
+{
+       /* write pretty header */
+       /* write revoked tp special marker */
+       /* write next probe time */
+       /* write anchors */
+}
+
+int autr_process_prime(struct module_env* env, struct val_env* ve,
+       struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset)
+{
+       struct val_anchors* anchors = env->anchors;
+       /* autotrust update trust anchors */
+
+       return 1;
+}
index 1ce209d98ec17212f354b5f03cdc9cf7f58ccf0d..1b6b625de17be8a984533203d14fcaa30f7c9977 100644 (file)
 #define VALIDATOR_AUTOTRUST_H
 #include "util/rbtree.h"
 struct val_anchors;
+struct trust_anchor;
+struct ub_packed_rrset_key;
+struct module_env;
+struct val_env;
 
 /** Autotrust anchor states */
 typedef enum {
@@ -57,7 +61,11 @@ typedef enum {
 /** 
  * Autotrust metadata for one trust anchor key.
  */
-struct autr_ta_data {
+struct autr_ta {
+       /** next key */
+       struct autr_ta* next;
+       /** the RR */
+       ldns_rr* rr;
        /** 5011 state */
        autr_state_t s;
        /** last update of key */
@@ -78,7 +86,7 @@ struct autr_point_data {
        const char* file;
        /** next probe time */
        uint32_t next_probe_time;
-       /** rbtree node for probe sort */
+       /** rbtree node for probe sort, key is struct trust_anchor */
        rbnode_t pnode;
 
        /** last queried DNSKEY set */
@@ -94,6 +102,8 @@ struct autr_point_data {
        uint8_t valid;
        /** number of missing DNSKEYs */
        uint8_t missing;
+       /** the keys */
+       struct autr_ta* keys;
 };
 
 /** 
@@ -122,11 +132,35 @@ int probetree_cmp(const void* x, const void* y);
 /**
  * Read autotrust file.
  * @param anchors: the anchors structure.
- * @param parsebuf: buffer temporary for parsing data.
  * @param nm: name of the file (copied).
  * @return false on failure.
  */
-int autr_read_file(struct val_anchors* anchors, ldns_buffer* parsebuf,
-       const char* nm);
+int autr_read_file(struct val_anchors* anchors, const char* nm);
+
+/**
+ * Write autotrust file.
+ * @param tp: trust point to write.
+ */
+void autr_write_file(struct trust_anchor* tp);
+
+/**
+ * Delete autr anchor, deletes the autr data but does not do
+ * unlinking from trees, caller does that.
+ * @param tp: trust point to delete.
+ */
+void autr_point_delete(struct trust_anchor* tp);
+
+/**
+ * Perform autotrust processing.
+ * @param env: qstate environment with the anchors structure.
+ * @param ve: validator environment for verification of rrsigs.
+ * @param tp: trust anchor to process.
+ * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result).
+ *     allocated in a region. Has not been validated yet.
+ * @return false if trust anchor was revoked completely.
+ *     Otherwise logs errors to log, does not change return value.
+ */
+int autr_process_prime(struct module_env* env, struct val_env* ve,
+       struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset);
 
 #endif /* VALIDATOR_AUTOTRUST_H */
index e442044d416906f67e3f7e8762145360562b2caa..ce8d1b86259e32fb9919f7c7cee9d455cb131ffe 100644 (file)
@@ -89,14 +89,31 @@ anchors_create()
                anchors_delete(a);
                return NULL;
        }
+       lock_basic_init(&a->lock);
+       lock_protect(&a->lock, a, sizeof(*a));
        return a;
 }
 
+/** destroy locks in tree and delete autotrust anchors */
+static void
+anchors_delfunc(rbnode_t* elem, void* ATTR_UNUSED(arg))
+{
+       struct trust_anchor* ta = (struct trust_anchor*)elem;
+       if(ta->autr) {
+               autr_point_delete(ta);
+       } else {
+               lock_basic_destroy(&ta->lock);
+       }
+}
+
 void 
 anchors_delete(struct val_anchors* anchors)
 {
        if(!anchors)
                return;
+       lock_unprotect(&anchors->lock, anchors);
+       lock_basic_destroy(&anchors->lock);
+       traverse_postorder(anchors->tree, anchors_delfunc, NULL);
        free(anchors->tree);
        regional_destroy(anchors->region);
        autr_global_delete(anchors->autr);
@@ -109,10 +126,13 @@ init_parents(struct val_anchors* anchors)
 {
        struct trust_anchor* node, *prev = NULL, *p;
        int m; 
+       lock_basic_lock(&anchors->lock);
        RBTREE_FOR(node, struct trust_anchor*, anchors->tree) {
+               lock_basic_lock(&node->lock);
                node->parent = NULL;
                if(!prev || prev->dclass != node->dclass) {
                        prev = node;
+                       lock_basic_unlock(&node->lock);
                        continue;
                }
                (void)dname_lab_cmp(prev->name, prev->namelabs, node->name, 
@@ -128,8 +148,10 @@ init_parents(struct val_anchors* anchors)
                                node->parent = p;
                                break;
                        }
+               lock_basic_unlock(&node->lock);
                prev = node;
        }
+       lock_basic_unlock(&anchors->lock);
 }
 
 struct trust_anchor*
@@ -138,12 +160,18 @@ anchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs,
 {
        struct trust_anchor key;
        rbnode_t* n;
+       if(!name) return NULL;
        key.node.key = &key;
        key.name = name;
        key.namelabs = namelabs;
        key.namelen = namelen;
        key.dclass = dclass;
+       lock_basic_lock(&anchors->lock);
        n = rbtree_search(anchors->tree, &key);
+       if(n) {
+               lock_basic_lock(&((struct trust_anchor*)n->key)->lock);
+       }
+       lock_basic_unlock(&anchors->lock);
        if(!n)
                return NULL;
        return (struct trust_anchor*)n->key;
@@ -167,7 +195,10 @@ anchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs,
        ta->namelabs = namelabs;
        ta->namelen = namelen;
        ta->dclass = dclass;
+       lock_basic_init(&ta->lock);
+       lock_basic_lock(&anchors->lock);
        r = rbtree_insert(anchors->tree, &ta->node);
+       lock_basic_unlock(&anchors->lock);
        log_assert(r != NULL);
        return ta;
 }
@@ -236,22 +267,29 @@ anchor_store_new_key(struct val_anchors* anchors, uint8_t* name, uint16_t type,
                ta = anchor_new_ta(anchors, name, namelabs, namelen, dclass);
                if(!ta)
                        return NULL;
+               lock_basic_lock(&ta->lock);
        }
-       if(!rdata)
+       if(!rdata) {
+               lock_basic_unlock(&ta->lock);
                return ta;
+       }
        /* look for duplicates */
        if(anchor_find_key(ta, rdata, rdata_len, type)) {
+               lock_basic_unlock(&ta->lock);
                return ta;
        }
        k = anchor_new_ta_key(anchors, rdata, rdata_len, type);
-       if(!k)
+       if(!k) {
+               lock_basic_unlock(&ta->lock);
                return NULL;
+       }
        /* add new key */
        if(type == LDNS_RR_TYPE_DS)
                ta->numDS++;
        else    ta->numDNSKEY++;
        k->next = ta->keylist;
        ta->keylist = k;
+       lock_basic_unlock(&ta->lock);
        return ta;
 }
 
@@ -895,15 +933,20 @@ anchors_assemble_rrsets(struct val_anchors* anchors)
        struct trust_anchor* ta;
        struct trust_anchor* next;
        size_t nods, nokey;
+       lock_basic_lock(&anchors->lock);
        ta=(struct trust_anchor*)rbtree_first(anchors->tree);
        while((rbnode_t*)ta != RBTREE_NULL) {
                next = (struct trust_anchor*)rbtree_next(&ta->node);
+               lock_basic_lock(&ta->lock);
                if(ta->numDS == 0 && ta->numDNSKEY == 0) {
+                       lock_basic_unlock(&ta->lock);
                        ta = next; /* skip unsigned entries, nothing to do */
                        continue;
                }
                if(!anchors_assemble(anchors, ta)) {
                        log_err("out of memory");
+                       lock_basic_unlock(&ta->lock);
+                       lock_basic_unlock(&anchors->lock);
                        return 0;
                }
                nods = anchors_ds_unsupported(ta);
@@ -926,8 +969,10 @@ anchors_assemble_rrsets(struct val_anchors* anchors)
                                " upgrade unbound and openssl)", b);
                        (void)rbtree_delete(anchors->tree, &ta->node);
                }
+               lock_basic_unlock(&ta->lock);
                ta = next;
        }
+       lock_basic_unlock(&anchors->lock);
        return 1;
 }
 
@@ -982,27 +1027,35 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
                }
        }
        if(cfg->dlv_anchor_file && cfg->dlv_anchor_file[0] != 0) {
+               struct trust_anchor* dlva;
                nm = cfg->dlv_anchor_file;
                if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
                        cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
                        nm += strlen(cfg->chrootdir);
-               if(!(anchors->dlv_anchor = anchor_read_file(anchors, parsebuf,
+               if(!(dlva = anchor_read_file(anchors, parsebuf,
                        nm, 1))) {
                        log_err("error reading dlv-anchor-file: %s", 
                                cfg->dlv_anchor_file);
                        ldns_buffer_free(parsebuf);
                        return 0;
                }
+               lock_basic_lock(&anchors->lock);
+               anchors->dlv_anchor = dlva;
+               lock_basic_unlock(&anchors->lock);
        }
        for(f = cfg->dlv_anchor_list; f; f = f->next) {
+               struct trust_anchor* dlva;
                if(!f->str || f->str[0] == 0) /* empty "" */
                        continue;
-               if(!(anchors->dlv_anchor = anchor_store_str(
+               if(!(dlva = anchor_store_str(
                        anchors, parsebuf, f->str))) {
                        log_err("error in dlv-anchor: \"%s\"", f->str);
                        ldns_buffer_free(parsebuf);
                        return 0;
                }
+               lock_basic_lock(&anchors->lock);
+               anchors->dlv_anchor = dlva;
+               lock_basic_unlock(&anchors->lock);
        }
        for(f = cfg->auto_trust_anchor_file_list; f; f = f->next) {
                if(!f->str || f->str[0] == 0) /* empty "" */
@@ -1011,7 +1064,7 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
                if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
                        cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
                        nm += strlen(cfg->chrootdir);
-               if(!autr_read_file(anchors, parsebuf, nm)) {
+               if(!autr_read_file(anchors, nm)) {
                        log_err("error reading auto-trust-anchor-file: %s", 
                                f->str);
                        ldns_buffer_free(parsebuf);
@@ -1037,6 +1090,7 @@ anchors_lookup(struct val_anchors* anchors,
        key.namelabs = dname_count_labels(qname);
        key.namelen = qname_len;
        key.dclass = qclass;
+       lock_basic_lock(&anchors->lock);
        if(rbtree_find_less_equal(anchors->tree, &key, &res)) {
                /* exact */
                result = (struct trust_anchor*)res;
@@ -1044,8 +1098,10 @@ anchors_lookup(struct val_anchors* anchors,
                /* smaller element (or no element) */
                int m;
                result = (struct trust_anchor*)res;
-               if(!result || result->dclass != qclass)
+               if(!result || result->dclass != qclass) {
+                       lock_basic_unlock(&anchors->lock);
                        return NULL;
+               }
                /* count number of labels matched */
                (void)dname_lab_cmp(result->name, result->namelabs, key.name,
                        key.namelabs, &m);
@@ -1055,6 +1111,10 @@ anchors_lookup(struct val_anchors* anchors,
                        result = result->parent;
                }
        }
+       if(result) {
+               lock_basic_lock(&result->lock);
+       }
+       lock_basic_unlock(&anchors->lock);
        return result;
 }
 
index a5274d2693624970a2555fd88b4dc9f4c29b413a..af530ba2e28f7999d0bf9cbb7359961cbf7da581 100644 (file)
 #ifndef VALIDATOR_VAL_ANCHOR_H
 #define VALIDATOR_VAL_ANCHOR_H
 #include "util/rbtree.h"
+#include "util/locks.h"
 struct regional;
 struct trust_anchor;
 struct config_file;
 struct ub_packed_rrset_key;
-struct autr_ta_data;
 struct autr_point_data;
 struct autr_global_data;
 
@@ -54,6 +54,8 @@ struct autr_global_data;
  * Trust anchor store.
  */
 struct val_anchors {
+       /** lock on trees */
+       lock_basic_t lock;
        /** region where trust anchors are allocated */
        struct regional* region;
        /**
@@ -81,8 +83,6 @@ struct ta_key {
        size_t len;
        /** DNS type (host format) of the key, DS or DNSKEY */
        uint16_t type;
-       /** Autotrust ta key state, or NULL */
-       struct autr_ta_data* autr;
 };
 
 /**
@@ -92,6 +92,8 @@ struct ta_key {
 struct trust_anchor {
        /** rbtree node, key is this structure */
        rbnode_t node;
+       /** lock on the entire anchor and its keys; for autotrust changes */
+       lock_basic_t lock;
        /** name of this trust anchor */
        uint8_t* name;
        /** length of name */
@@ -147,7 +149,7 @@ int anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg);
  * @param qname: query name, uncompressed wireformat.
  * @param qname_len: length of qname.
  * @param qclass: class to query for.
- * @return the trust anchor or NULL if none is found.
+ * @return the trust anchor or NULL if none is found. The anchor is locked.
  */
 struct trust_anchor* anchors_lookup(struct val_anchors* anchors,
        uint8_t* qname, size_t qname_len, uint16_t qclass);
@@ -159,7 +161,7 @@ struct trust_anchor* anchors_lookup(struct val_anchors* anchors,
  * @param namelabs: labels in name
  * @param namelen: length of name
  * @param dclass: class of trust anchor
- * @return NULL if not found.
+ * @return NULL if not found. The anchor is locked.
  */
 struct trust_anchor* anchor_find(struct val_anchors* anchors, 
        uint8_t* name, int namelabs, size_t namelen, uint16_t dclass);
index 829f93f68fdfaec31ee0b9b09e7d4037b2a65f70..705e828f4ef642a1657ad180c471f5025b8d7074 100644 (file)
@@ -712,6 +712,17 @@ val_check_nonsecure(struct val_env* ve, struct reply_info* rep)
        }
 }
 
+/** check no anchor and unlock */
+static int
+check_no_anchor(struct val_anchors* anchors, uint8_t* nm, size_t l, uint16_t c)
+{
+       struct trust_anchor* ta;
+       if((ta=anchors_lookup(anchors, nm, l, c))) {
+               lock_basic_unlock(&ta->lock);
+       }
+       return !ta;
+}
+
 void 
 val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors, 
        struct rrset_cache* r, struct module_env* env)
@@ -721,7 +732,7 @@ val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors,
        for(i=0; i<rep->rrset_count; i++) {
                d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
                if(d->security == sec_status_unchecked &&
-                  !anchors_lookup(anchors, rep->rrsets[i]->rk.dname,
+                  check_no_anchor(anchors, rep->rrsets[i]->rk.dname,
                        rep->rrsets[i]->rk.dname_len, 
                        ntohs(rep->rrsets[i]->rk.rrset_class))) 
                {       
index 526ff8dc95d719f545bffc772aedf00fa360a288..b81dc215eee32728ece116b993518c8ff9da4979 100644 (file)
@@ -48,6 +48,7 @@
 #include "validator/val_nsec.h"
 #include "validator/val_nsec3.h"
 #include "validator/val_neg.h"
+#include "validator/autotrust.h"
 #include "services/cache/dns.h"
 #include "util/data/dname.h"
 #include "util/module.h"
@@ -372,6 +373,15 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
         * query, and its a 'normal' for iterator as well */
        vq->wait_prime_ta = 1; /* to elicit PRIME_RESP_STATE processing 
                from the validator inform_super() routine */
+       /* store trust anchor name for later lookup when prime returns */
+       vq->trust_anchor_name = regional_alloc_init(qstate->region,
+               toprime->name, toprime->namelen);
+       vq->trust_anchor_len = toprime->namelen;
+       vq->trust_anchor_labs = toprime->namelabs;
+       if(!vq->trust_anchor_name) {
+               log_err("Could not prime trust anchor: out of memory");
+               return 0;
+       }
        return 1;
 }
 
@@ -1160,6 +1170,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
 {
        uint8_t* lookup_name;
        size_t lookup_len;
+       struct trust_anchor* anchor;
        enum val_classification subtype = val_classify_response(
                qstate->query_flags, &qstate->qinfo, &vq->qchase, 
                vq->orig_msg->rep, vq->rrset_skip);
@@ -1197,7 +1208,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
        vq->key_entry = NULL;
        vq->empty_DS_name = NULL;
        vq->ds_rrset = 0;
-       vq->trust_anchor = anchors_lookup(qstate->env->anchors, 
+       anchor = anchors_lookup(qstate->env->anchors, 
                lookup_name, lookup_len, vq->qchase.qclass);
 
        /* Determine the signer/lookup name */
@@ -1216,13 +1227,11 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
 
        /* for NXDOMAIN it could be signed by a parent of the trust anchor */
        if(subtype == VAL_CLASS_NAMEERROR && vq->signer_name &&
-               vq->trust_anchor &&
-               dname_strict_subdomain_c(vq->trust_anchor->name, lookup_name)){
-               while(vq->trust_anchor && dname_strict_subdomain_c(
-                       vq->trust_anchor->name, lookup_name)) {
-                       vq->trust_anchor = vq->trust_anchor->parent;
-               }
-               if(!vq->trust_anchor) { /* unsigned parent denies anchor*/
+               anchor && dname_strict_subdomain_c(anchor->name, lookup_name)){
+               lock_basic_unlock(&anchor->lock);
+               anchor = anchors_lookup(qstate->env->anchors, 
+                       lookup_name, lookup_len, vq->qchase.qclass);
+               if(!anchor) { /* unsigned parent denies anchor*/
                        verbose(VERB_QUERY, "unsigned parent zone denies"
                                " trust anchor, indeterminate");
                        vq->chase_reply->security = sec_status_indeterminate;
@@ -1248,7 +1257,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
                vq->qchase.qclass, qstate->region, *qstate->env->now);
 
        /* there is no key(from DLV) and no trust anchor */
-       if(vq->key_entry == NULL && vq->trust_anchor == NULL) {
+       if(vq->key_entry == NULL && anchor == NULL) {
                /*response isn't under a trust anchor, so we cannot validate.*/
                vq->chase_reply->security = sec_status_indeterminate;
                /* go to finished state to cache this result */
@@ -1257,16 +1266,14 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
        }
        /* if not key, or if keyentry is *above* the trustanchor, i.e.
         * the keyentry is based on another (higher) trustanchor */
-       else if(vq->key_entry == NULL || (vq->trust_anchor &&
-               dname_strict_subdomain_c(vq->trust_anchor->name, 
-               vq->key_entry->name))) {
+       else if(vq->key_entry == NULL || (anchor &&
+               dname_strict_subdomain_c(anchor->name, vq->key_entry->name))) {
                /* trust anchor is an 'unsigned' trust anchor */
-               if(vq->trust_anchor && vq->trust_anchor->numDS == 0 &&
-                       vq->trust_anchor->numDNSKEY == 0) {
+               if(anchor && anchor->numDS == 0 && anchor->numDNSKEY == 0) {
                        vq->chase_reply->security = sec_status_insecure;
-                       val_mark_insecure(vq->chase_reply, 
-                               vq->trust_anchor->name, 
+                       val_mark_insecure(vq->chase_reply, anchor->name, 
                                qstate->env->rrset_cache, qstate->env);
+                       lock_basic_unlock(&anchor->lock);
                        vq->dlv_checked=1; /* skip DLV check */
                        /* go to finished state to cache this result */
                        vq->state = VAL_FINISHED_STATE;
@@ -1274,13 +1281,21 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
                }
                /* fire off a trust anchor priming query. */
                verbose(VERB_DETAIL, "prime trust anchor");
-               if(!prime_trust_anchor(qstate, vq, id, vq->trust_anchor))
+               if(!prime_trust_anchor(qstate, vq, id, anchor)) {
+                       lock_basic_unlock(&anchor->lock);
                        return val_error(qstate, id);
+               }
+               lock_basic_unlock(&anchor->lock);
                /* and otherwise, don't continue processing this event.
                 * (it will be reactivated when the priming query returns). */
                vq->state = VAL_FINDKEY_STATE;
                return 0;
-       } else if(key_entry_isnull(vq->key_entry)) {
+       }
+       if(anchor) {
+               lock_basic_unlock(&anchor->lock);
+       }
+
+       if(key_entry_isnull(vq->key_entry)) {
                /* response is under a null key, so we cannot validate
                 * However, we do set the status to INSECURE, since it is 
                 * essentially proven insecure. */
@@ -2031,8 +2046,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
 /**
  * Evaluate the response to a priming request.
  *
- * @param rcode: rcode return value.
- * @param msg: message return value (allocated in a the wrong region).
+ * @param dnskey_rrset: DNSKEY rrset (can be NULL if none) in prime reply.
+ *     (this rrset is allocated in the wrong region, not the qstate).
  * @param ta: trust anchor.
  * @param qstate: qstate that needs key.
  * @param id: module id.
@@ -2042,19 +2057,13 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
  *     Bad key (validation failed).
  */
 static struct key_entry_key*
-primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta,
-       struct module_qstate* qstate, int id)
+primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, 
+       struct trust_anchor* ta, struct module_qstate* qstate, int id)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
-       struct ub_packed_rrset_key* dnskey_rrset = NULL;
        struct key_entry_key* kkey = NULL;
        enum sec_status sec = sec_status_unchecked;
 
-       if(rcode == LDNS_RCODE_NOERROR) {
-               dnskey_rrset = reply_find_rrset_section_an(msg->rep,
-                       ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY,
-                       ta->dclass);
-       }
        if(!dnskey_rrset) {
                log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
                        "could not fetch DNSKEY rrset", 
@@ -2069,7 +2078,6 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta,
                        log_err("out of memory: allocate fail prime key");
                        return NULL;
                }
-               key_cache_insert(ve->kcache, kkey);
                return kkey;
        }
        /* attempt to verify with trust anchor DS and DNSKEY */
@@ -2119,14 +2127,11 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta,
                        log_err("out of memory: allocate null prime key");
                        return NULL;
                }
-               key_cache_insert(ve->kcache, kkey);
                return kkey;
        }
 
        log_nametypeclass(VERB_DETAIL, "Successfully primed trust anchor", 
                ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
-       /* store the freshly primed entry in the cache */
-       key_cache_insert(ve->kcache, kkey);
        return kkey;
 }
 
@@ -2422,10 +2427,39 @@ static void
 process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
        int id, int rcode, struct dns_msg* msg)
 {
+       struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
+       struct ub_packed_rrset_key* dnskey_rrset = NULL;
+       struct trust_anchor* ta = anchor_find(qstate->env->anchors, 
+               vq->trust_anchor_name, vq->trust_anchor_labs,
+               vq->trust_anchor_len, vq->qchase.qclass);
+       if(!ta) {
+               /* trust anchor revoked, restart with less anchors */
+               vq->state = VAL_INIT_STATE;
+               if(!vq->trust_anchor_name)
+                       vq->state = VAL_VALIDATE_STATE; /* break a loop */
+               vq->trust_anchor_name = NULL;
+               return;
+       }
        /* Fetch and validate the keyEntry that corresponds to the 
         * current trust anchor. */
-       vq->key_entry = primeResponseToKE(rcode, msg, vq->trust_anchor, 
-               qstate, id);
+       if(rcode == LDNS_RCODE_NOERROR) {
+               dnskey_rrset = reply_find_rrset_section_an(msg->rep,
+                       ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY,
+                       ta->dclass);
+       }
+       if(ta->autr) {
+               if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) {
+                       /* trust anchor revoked, restart with less anchors */
+                       vq->state = VAL_INIT_STATE;
+                       vq->trust_anchor_name = NULL;
+                       return;
+               }
+       }
+       vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id);
+       lock_basic_unlock(&ta->lock);
+       if(vq->key_entry)
+               /* store the freshly primed entry in the cache */
+               key_cache_insert(ve->kcache, vq->key_entry);
 
        /* If the result of the prime is a null key, skip the FINDKEY state.*/
        if(!vq->key_entry || key_entry_isnull(vq->key_entry) ||
index cdc4796192de21e09786f0e11172c7d229e42575..9587fedaee3ed6a9951e375c788f39d5f34ebbb8 100644 (file)
@@ -177,8 +177,12 @@ struct val_qstate {
         */
        size_t rrset_skip;
 
-       /** the trust anchor rrset */
-       struct trust_anchor* trust_anchor;
+       /** trust anchor name */
+       uint8_t* trust_anchor_name;
+       /** trust anchor labels */
+       int trust_anchor_labs;
+       /** trust anchor length */
+       size_t trust_anchor_len;
 
        /** the DS rrset */
        struct ub_packed_rrset_key* ds_rrset;