do not cache nonRD replies in msg cache, the rrset cache is used for that.

store verification status in rrset cache to enable security for nonRD
replies and also speed up processing.


git-svn-id: https://unbound.nlnetlabs.nl/svn/trunk@550 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
wouter 2007-08-27 13:46:05 +00:00
parent 53de4306c6
commit ee53b5fef8
7 changed files with 122 additions and 15 deletions

View File

@ -314,13 +314,15 @@ check_delegation_secure(struct reply_info *rep)
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;
}
@ -336,7 +338,8 @@ deleg_remove_nonsecure_additional(struct reply_info* rep)
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*)*

View File

@ -3,6 +3,9 @@
- 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.

View File

@ -1355,10 +1355,15 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
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) {

View File

@ -115,6 +115,10 @@ need_to_update_rrset(void* nd, void* cd, uint32_t timenow, int equal)
{
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,
@ -306,3 +310,58 @@ rrset_array_unlock_touch(struct rrset_cache* r, struct region* scratch,
}
}
}
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);
}

View File

@ -184,4 +184,26 @@ void rrset_array_unlock(struct rrset_ref* ref, size_t count);
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 */

View File

@ -43,10 +43,12 @@
#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,
@ -270,6 +272,14 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
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);
@ -284,10 +294,12 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
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;

View File

@ -1163,10 +1163,11 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
}
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);
}
@ -1177,9 +1178,11 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
}
/* 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;