]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
do not cache nonRD replies in msg cache, the rrset cache is used for that.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 27 Aug 2007 13:46:05 +0000 (13:46 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 27 Aug 2007 13:46:05 +0000 (13:46 +0000)
store verification status in rrset cache to enable security for nonRD
replies and also speed up processing.

git-svn-id: file:///svn/unbound/trunk@550 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/Changelog
iterator/iterator.c
services/cache/rrset.c
services/cache/rrset.h
validator/val_utils.c
validator/validator.c

index 2f0057a43a8e8a91eeac096208caf516581b97fe..2897540e74f5bc396cc17667081fcb122e749566 100644 (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*)* 
index 9bf81ad6814d1614e25aa95d1faa2484d0b146db..dc32fb53d6c92e30c1a98fac20f6b3ba05daa0b1 100644 (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.
index 6b3380db834432f08d9f7424241f1d45f83e72c4..6d63d6c6c2381262f11de24a8c01e01def50cc0f 100644 (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) {
index 4a9789b1ad7c58916e8748e73bcd94eb6381c716..4d8d661df19ab029d241f253574abad6bb6de43b 100644 (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);
+}
index 19fbbe09e954c4cbee3033f4426606d959eef80c..22ae295838146259a66f0c3bd51158842ea4b33f 100644 (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 */
index 48e809238db6e028fb23dd9ec38ed701bdafc9a7..34ac447d6f3104fee90cbbfb3e2396e84037b8ac 100644 (file)
 #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;
index 8dcedf265853899eb162bc06cdbf3af252fc3fa4..ed3ac6bb9384282c37df432c2c023c8e4f26f440 100644 (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;