autotrust work

git-svn-id: file:///svn/unbound/trunk@1760 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-08-13 15:32:04 +00:00
parent a85b563d37
commit 21e791248f
11 changed files with 419 additions and 120 deletions

View file

@ -1,3 +1,6 @@
13 August 2009: Wouter
- autotrust read anchor files. locked trust anchors.
12 August 2009: Wouter
- autotrust import work.

View 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,

View 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");
}

View 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);
}

View file

@ -41,12 +41,11 @@
#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");
/* 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 = time(NULL);
*/
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)
if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)
return 0;
if(ta->len < 2+2)
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 (ta_dnskey_flags(ta)&DNSKEY_BIT_SEP);
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)
{
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, ';'))
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)
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->autr->s == AUTR_STATE_MISSING)
else if (ta->s == AUTR_STATE_MISSING)
tp->autr->missing ++;
}
}
else
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;
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;
}

View file

@ -43,6 +43,10 @@
#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 */

View 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;
}

View file

@ -42,11 +42,11 @@
#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);

View 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)))
{

View 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) ||

View 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;