+13 August 2009: Wouter
+ - autotrust read anchor files. locked trust anchors.
+
12 August 2009: Wouter
- autotrust import work.
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,
(lock->type==check_lock_rwlock)?"rwlock": "badtype")), err);
log_err("complete status display:");
total_debug_info();
+ abort();
fatal_exit("bailing out");
}
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"));
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);
}
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);
}
#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;
}
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;
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))
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)
{
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;
}
else
{
comments += pos;
- ta->pending_count = atoi(comments);
+ ta->pending_count = (uint8_t)atoi(comments);
}
/* read last change */
}
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;
/** 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",
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 */
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;
+}
#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 {
/**
* 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 */
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 */
uint8_t valid;
/** number of missing DNSKEYs */
uint8_t missing;
+ /** the keys */
+ struct autr_ta* keys;
};
/**
/**
* 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 */
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);
{
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,
node->parent = p;
break;
}
+ lock_basic_unlock(&node->lock);
prev = node;
}
+ lock_basic_unlock(&anchors->lock);
}
struct trust_anchor*
{
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;
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;
}
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;
}
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);
" 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;
}
}
}
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 "" */
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);
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;
/* 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);
result = result->parent;
}
}
+ if(result) {
+ lock_basic_lock(&result->lock);
+ }
+ lock_basic_unlock(&anchors->lock);
return result;
}
#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;
* Trust anchor store.
*/
struct val_anchors {
+ /** lock on trees */
+ lock_basic_t lock;
/** region where trust anchors are allocated */
struct regional* region;
/**
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;
};
/**
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 */
* @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);
* @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);
}
}
+/** 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)
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)))
{
#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"
* 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;
}
{
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);
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 */
/* 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;
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 */
}
/* 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;
}
/* 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. */
/**
* 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.
* 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",
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 */
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;
}
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) ||
*/
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;