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; size_t num = rep->an_numrrsets + rep->ns_numrrsets;
/* check if answer and authority are OK */ /* check if answer and authority are OK */
for(i=0; i<num; i++) { 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) if(s < sec)
sec = s; sec = s;
} }
/* in additional, only unchecked triggers revalidation */ /* in additional, only unchecked triggers revalidation */
for(i=num; i<rep->rrset_count; i++) { 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) if(s == sec_status_unchecked)
return s; return s;
} }
@ -336,7 +338,8 @@ deleg_remove_nonsecure_additional(struct reply_info* rep)
enum sec_status s; enum sec_status s;
for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { 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) { if(s != sec_status_secure) {
memmove(rep->rrsets+i, rep->rrsets+i+1, memmove(rep->rrsets+i, rep->rrsets+i+1,
sizeof(struct ub_packed_rrset_key*)* sizeof(struct ub_packed_rrset_key*)*

View File

@ -3,6 +3,9 @@
- answer norecursive from cache if possible. - answer norecursive from cache if possible.
- honor clean_additional setting when returning secure non-recursive - honor clean_additional setting when returning secure non-recursive
referrals. 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 24 August 2007: Wouter
- message is bogus if unsecure authority rrsets are present. - 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"); log_err("prepend rrsets: out of memory");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
} }
/* store message with the finished prepended items */ /* store message with the finished prepended items,
if(!iter_dns_store(qstate->env, &qstate->qinfo, * but only if we did recursion. The nonrecursion referral
iq->response->rep, 0)) * from cache does not need to be stored in the msg cache. */
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); 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, if(query_dname_compare(qstate->qinfo.qname,
iq->response->qinfo.qname) == 0) { 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* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; 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 */ /* o if current RRset is more trustworthy - insert it */
if( newd->trust > cached->trust ) { if( newd->trust > cached->trust ) {
/* if the cached rrset is bogus, and this one equal, /* 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, void rrset_array_unlock_touch(struct rrset_cache* r, struct region* scratch,
struct rrset_ref* ref, size_t count); 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 */ #endif /* SERVICES_CACHE_RRSET_H */

View File

@ -43,10 +43,12 @@
#include "validator/validator.h" #include "validator/validator.h"
#include "validator/val_kentry.h" #include "validator/val_kentry.h"
#include "validator/val_sigcrypt.h" #include "validator/val_sigcrypt.h"
#include "services/cache/rrset.h"
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/packed_rrset.h" #include "util/data/packed_rrset.h"
#include "util/data/dname.h" #include "util/data/dname.h"
#include "util/net_help.h" #include "util/net_help.h"
#include "util/module.h"
enum val_classification enum val_classification
val_classify_response(struct query_info* qinf, struct reply_info* rep, 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)); ntohs(rrset->rk.rrset_class));
return d->security; 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, log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
sec = dnskeyset_verify_rrset(env, ve, rrset, keys); 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; d->trust = rrset_trust_validated;
else if(sec == sec_status_bogus) { else if(sec == sec_status_bogus) {
/* update ttl for rrset to fixed value. */ /* 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 /* leave RR specific TTL: not used for determine
* if RRset timed out and clients see proper value. */ * 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; 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) { if(vq->orig_msg->rep->security == sec_status_secure) {
/* Do not store the validated status of the dropped RRsets. /* If the message is secure, check that all rrsets are
* (only secure is reused). These rrsets are apparantly * secure (i.e. some inserted RRset for CNAME chain with
* added on maliciously, or are unsigned additional data * a different signer name). And drop additional rrsets
* This may cause the message to become bogus. */ * 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); 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 */ /* store results in cache */
if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, if(qstate->query_flags&BIT_RD) {
vq->orig_msg->rep, 0)) { if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
log_err("out of memory caching validator results"); vq->orig_msg->rep, 0)) {
log_err("out of memory caching validator results");
}
} }
qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = vq->orig_msg; qstate->return_msg = vq->orig_msg;