size_t num = rep->an_numrrsets + rep->ns_numrrsets;
/* check if answer and authority are OK */
for(i=0; i<num; i++) {
- s = ((struct packed_rrset_data*)rep->rrsets[i])->security;
+ s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
+ ->security;
if(s < sec)
sec = s;
}
/* in additional, only unchecked triggers revalidation */
for(i=num; i<rep->rrset_count; i++) {
- s = ((struct packed_rrset_data*)rep->rrsets[i])->security;
+ s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
+ ->security;
if(s == sec_status_unchecked)
return s;
}
enum sec_status s;
for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
- s = ((struct packed_rrset_data*)rep->rrsets[i])->security;
+ s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
+ ->security;
if(s != sec_status_secure) {
memmove(rep->rrsets+i, rep->rrsets+i+1,
sizeof(struct ub_packed_rrset_key*)*
- answer norecursive from cache if possible.
- honor clean_additional setting when returning secure non-recursive
referrals.
+ - do not store referral in msg cache for nonRD queries.
+ - store verification status in the rrset cache to speed up future
+ verification.
24 August 2007: Wouter
- message is bogus if unsecure authority rrsets are present.
log_err("prepend rrsets: out of memory");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
- /* store message with the finished prepended items */
- if(!iter_dns_store(qstate->env, &qstate->qinfo,
- iq->response->rep, 0))
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ /* store message with the finished prepended items,
+ * but only if we did recursion. The nonrecursion referral
+ * from cache does not need to be stored in the msg cache. */
+ if(qstate->query_flags&BIT_RD) {
+ if(!iter_dns_store(qstate->env, &qstate->qinfo,
+ iq->response->rep, 0))
+ return error_response(qstate, id,
+ LDNS_RCODE_SERVFAIL);
+ }
}
if(query_dname_compare(qstate->qinfo.qname,
iq->response->qinfo.qname) == 0) {
{
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
+ /* o store if rrset has been validated */
+ if( newd->security > cached->security) {
+ return 1;
+ }
/* o if current RRset is more trustworthy - insert it */
if( newd->trust > cached->trust ) {
/* if the cached rrset is bogus, and this one equal,
}
}
}
+
+void
+rrset_update_sec_status(struct rrset_cache* r,
+ struct ub_packed_rrset_key* rrset)
+{
+ uint32_t now = (uint32_t)time(0);
+ struct packed_rrset_data* updata =
+ (struct packed_rrset_data*)rrset->entry.data;
+ struct lruhash_entry* e;
+ struct packed_rrset_data* cachedata;
+
+ e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 1);
+ if(!e)
+ return; /* not in the cache anymore */
+ cachedata = (struct packed_rrset_data*)e->data;
+ if(!rrsetdata_equal(updata, cachedata)) {
+ lock_rw_unlock(&e->lock);
+ return; /* rrset has changed in the meantime */
+ }
+ /* update the cached rrset */
+ cachedata->trust = updata->trust;
+ cachedata->security = updata->security;
+ cachedata->ttl = updata->ttl + now;
+ lock_rw_unlock(&e->lock);
+}
+
+void
+rrset_check_sec_status(struct rrset_cache* r,
+ struct ub_packed_rrset_key* rrset)
+{
+ uint32_t now = (uint32_t)time(0);
+ struct packed_rrset_data* updata =
+ (struct packed_rrset_data*)rrset->entry.data;
+ struct lruhash_entry* e;
+ struct packed_rrset_data* cachedata;
+
+ /* hash it again to make sure it has a hash */
+ rrset->entry.hash = rrset_key_hash(&rrset->rk);
+
+ e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 0);
+ if(!e)
+ return; /* not in the cache anymore */
+ cachedata = (struct packed_rrset_data*)e->data;
+ if(now > cachedata->ttl || !rrsetdata_equal(updata, cachedata)) {
+ lock_rw_unlock(&e->lock);
+ return; /* expired, or rrset has changed in the meantime */
+ }
+ if(cachedata->security > updata->security) {
+ updata->security = cachedata->security;
+ if(cachedata->security == sec_status_bogus)
+ updata->ttl = cachedata->ttl - now;
+ updata->trust = cachedata->trust;
+ }
+ lock_rw_unlock(&e->lock);
+}
void rrset_array_unlock_touch(struct rrset_cache* r, struct region* scratch,
struct rrset_ref* ref, size_t count);
+/**
+ * Update security status of an rrset. Looks up the rrset.
+ * If found, checks if rdata is equal.
+ * If so, it will update the security, trust and rrset-ttl values.
+ * @param r: the rrset cache.
+ * @param rrset: which rrset to attempt to update. This rrset is left
+ * untouched. The rrset in the cache is updated in-place.
+ */
+void rrset_update_sec_status(struct rrset_cache* r,
+ struct ub_packed_rrset_key* rrset);
+
+/**
+ * Looks up security status of an rrset. Looks up the rrset.
+ * If found, checks if rdata is equal, and entry did not expire.
+ * If so, it will update the security, trust and rrset-ttl values.
+ * @param r: the rrset cache.
+ * @param rrset: This rrset may change security status due to the cache.
+ * But its status will only improve, towards secure.
+ */
+void rrset_check_sec_status(struct rrset_cache* r,
+ struct ub_packed_rrset_key* rrset);
+
#endif /* SERVICES_CACHE_RRSET_H */
#include "validator/validator.h"
#include "validator/val_kentry.h"
#include "validator/val_sigcrypt.h"
+#include "services/cache/rrset.h"
#include "util/data/msgreply.h"
#include "util/data/packed_rrset.h"
#include "util/data/dname.h"
#include "util/net_help.h"
+#include "util/module.h"
enum val_classification
val_classify_response(struct query_info* qinf, struct reply_info* rep,
ntohs(rrset->rk.rrset_class));
return d->security;
}
+ /* check in the cache if verification has already been done */
+ rrset_check_sec_status(env->rrset_cache, rrset);
+ if(d->security == sec_status_secure) {
+ log_nametypeclass(VERB_ALGO, "verify rrset from cache",
+ rrset->rk.dname, ntohs(rrset->rk.type),
+ ntohs(rrset->rk.rrset_class));
+ return d->security;
+ }
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
sec = dnskeyset_verify_rrset(env, ve, rrset, keys);
d->trust = rrset_trust_validated;
else if(sec == sec_status_bogus) {
/* update ttl for rrset to fixed value. */
- d->ttl = time(0) + ve->bogus_ttl;
+ d->ttl = ve->bogus_ttl;
/* leave RR specific TTL: not used for determine
* if RRset timed out and clients see proper value. */
}
+ /* if status updated - store in cache for reuse */
+ rrset_update_sec_status(env->rrset_cache, rrset);
}
return sec;
}
if(vq->orig_msg->rep->security == sec_status_secure) {
- /* Do not store the validated status of the dropped RRsets.
- * (only secure is reused). These rrsets are apparantly
- * added on maliciously, or are unsigned additional data
- * This may cause the message to become bogus. */
+ /* If the message is secure, check that all rrsets are
+ * secure (i.e. some inserted RRset for CNAME chain with
+ * a different signer name). And drop additional rrsets
+ * that are not secure (if clean-additional option is set) */
+ /* this may cause the msg to be marked bogus */
val_check_nonsecure(ve, vq->orig_msg->rep);
}
}
/* store results in cache */
- if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 0)) {
- log_err("out of memory caching validator results");
+ if(qstate->query_flags&BIT_RD) {
+ if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
+ vq->orig_msg->rep, 0)) {
+ log_err("out of memory caching validator results");
+ }
}
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = vq->orig_msg;