]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that CD flag disables DNS64 processing, returning the DNSSEC
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 18 Nov 2014 15:15:57 +0000 (15:15 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 18 Nov 2014 15:15:57 +0000 (15:15 +0000)
  signed AAAA denial.

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

19 files changed:
daemon/cachedump.c
daemon/remote.c
daemon/worker.c
dns64/dns64.c
doc/Changelog
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
pythonmod/pythonmod_utils.c
services/cache/dns.c
services/cache/dns.h
services/mesh.c
services/mesh.h
util/data/msgreply.c
util/data/msgreply.h
util/fptr_wlist.c
util/fptr_wlist.h
util/module.h
validator/validator.c

index cf5b1a12c9a7e0e6d75ee3e3fc58a1d262a2ee1c..20a46ae4dffb4e1851708685a81ff4735519f96c 100644 (file)
@@ -664,7 +664,7 @@ load_msg(SSL* ssl, sldns_buffer* buf, struct worker* worker)
        if(!go_on) 
                return 1; /* skip this one, not all references satisfied */
 
-       if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) {
+       if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
                log_warn("error out of memory");
                return 0;
        }
index c49b07cd53690655b11c69f05501ffb4b3f61622..ff3d769d4e544b5024b84187b8e7fa9dc227ce11 100644 (file)
@@ -1095,8 +1095,13 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
        k.qname_len = nmlen;
        k.qtype = t;
        k.qclass = c;
-       h = query_info_hash(&k);
+       h = query_info_hash(&k, 0);
        slabhash_remove(worker->env.msg_cache, h, &k);
+       if(t == LDNS_RR_TYPE_AAAA) {
+               /* for AAAA also flush dns64 bit_cd packet */
+               h = query_info_hash(&k, BIT_CD);
+               slabhash_remove(worker->env.msg_cache, h, &k);
+       }
 }
 
 /** flush a type */
index f9067621385b49ac7780b8af7f030664f4ca4dd3..59ae9dfcefcbfd71c8b42f0ac623a9ff1eb6c493 100644 (file)
@@ -935,7 +935,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                        &repinfo->addr, repinfo->addrlen);
                goto send_reply;
        }
-       h = query_info_hash(&qinfo);
+       h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
        if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
                /* answer from cache - we have acquired a readlock on it */
                if(answer_from_cache(worker, &qinfo, 
index 963e727fed76241b75fd586f5d35c4565e2c16d1..eaaa26f7c91035b4a18f62896575eed46a9137b1 100644 (file)
@@ -399,7 +399,7 @@ handle_ipv6_ptr(struct module_qstate* qstate, int id)
 
     /* Create the new sub-query. */
     fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
-    if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
+    if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0,
                 &subq))
         return module_error;
     if (subq) {
@@ -451,7 +451,7 @@ generate_type_A_query(struct module_qstate* qstate, int id)
        /* Start the sub-query. */
        fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
        if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
-                                      &subq))
+                                      0, &subq))
        {
                verbose(VERB_ALGO, "dns64: sub-query creation failed");
                return module_error;
@@ -520,11 +520,13 @@ handle_event_moddone(struct module_qstate* qstate, int id)
      *
      *   - An internal query.
      *   - A query for a record type other than AAAA.
+     *   - CD FLAG was set on querier
      *   - An AAAA query for which an error was returned.
      *   - A successful AAAA query with an answer.
      */
        if ( (enum dns64_qstate)qstate->minfo[id] == DNS64_INTERNAL_QUERY
             || qstate->qinfo.qtype != LDNS_RR_TYPE_AAAA
+           || (qstate->query_flags & BIT_CD)
            || qstate->return_rcode != LDNS_RCODE_NOERROR  
            || (qstate->return_msg &&
                    qstate->return_msg->rep &&
@@ -813,7 +815,7 @@ dns64_inform_super(struct module_qstate* qstate, int id,
 
        /* Store the generated response in cache. */
        if (!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
-           0, 0, 0, NULL))
+           0, 0, 0, NULL, super->query_flags))
                log_err("out of memory");
 }
 
index 52232bd30140a985a8de28a677ee5597f10f9127..20b67c897f347e688e0d1cfb55d9ea187eaaa93f 100644 (file)
@@ -1,3 +1,7 @@
+18 November 2014: Wouter
+       - Fix that CD flag disables DNS64 processing, returning the DNSSEC
+         signed AAAA denial.
+
 17 November 2014: Wouter
        - Fix #627: SSL_CTX_load_verify_locations return code not properly
          checked.
index 4148c1268f78d208008acdd90010acf381152e7f..9d0aa698f99600b287fcb8e056880c15eb6713aa 100644 (file)
@@ -425,10 +425,10 @@ dns_copy_msg(struct dns_msg* from, struct regional* region)
 void 
 iter_dns_store(struct module_env* env, struct query_info* msgqinf,
        struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
-       struct regional* region)
+       struct regional* region, uint16_t flags)
 {
        if(!dns_cache_store(env, msgqinf, msgrep, is_referral, leeway,
-               pside, region))
+               pside, region, flags))
                log_err("out of memory: cannot store data in cache");
 }
 
@@ -457,7 +457,8 @@ causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
        fptr_ok(fptr_whitelist_modenv_detect_cycle(
                qstate->env->detect_cycle));
        return (*qstate->env->detect_cycle)(qstate, &qinf, 
-               (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming);
+               (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming,
+               qstate->is_valrec);
 }
 
 void 
index abdc68f3cd447dbda724a4faf6a2af4fa14bdc25..d7c2b68afa2d6562acdce28bd9824cc429f705c9 100644 (file)
@@ -124,6 +124,7 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
  * @param pside: true if dp is parentside, thus message is 'fresh' and NS
  *     can be prefetch-updates.
  * @param region: to copy modified (cache is better) rrs back to.
+ * @param flags: with BIT_CD for dns64 AAAA translated queries.
  * @return void, because we are not interested in alloc errors,
  *     the iterator and validator can operate on the results in their
  *     scratch space (the qstate.region) and are not dependent on the cache.
@@ -132,7 +133,7 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
  */
 void iter_dns_store(struct module_env* env, struct query_info* qinf,
        struct reply_info* rep, int is_referral, time_t leeway, int pside,
-       struct regional* region);
+       struct regional* region, uint16_t flags);
 
 /**
  * Select randomly with n/m probability.
index df5f645cc28c896ced40eab33016aa16f2e4415d..5bd5796b7cec4fb2d29396b2cd05a20eda27eba0 100644 (file)
@@ -257,7 +257,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
                verbose(VERB_ALGO, "error response for prefetch in cache");
                /* attempt to adjust the cache entry prefetch */
                if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo,
-                       NORR_TTL))
+                       NORR_TTL, qstate->query_flags))
                        return error_response(qstate, id, rcode);
                /* if that fails (not in cache), fall through to store err */
        }
@@ -270,7 +270,8 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
        /* do not waste time trying to validate this servfail */
        err.security = sec_status_indeterminate;
        verbose(VERB_ALGO, "store error response in message cache");
-       iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL);
+       iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL,
+               qstate->query_flags);
        return error_response(qstate, id, rcode);
 }
 
@@ -504,7 +505,8 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
        
        /* attach subquery, lookup existing or make a new one */
        fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
-       if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, &subq)) {
+       if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, 0,
+               &subq)) {
                return 0;
        }
        *subq_ret = subq;
@@ -938,7 +940,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
        } else {
                msg = dns_cache_lookup(qstate->env, iq->qchase.qname, 
                        iq->qchase.qname_len, iq->qchase.qtype, 
-                       iq->qchase.qclass, qstate->region, qstate->env->scratch);
+                       iq->qchase.qclass, qstate->query_flags,
+                       qstate->region, qstate->env->scratch);
                if(!msg && qstate->env->neg_cache) {
                        /* lookup in negative cache; may result in 
                         * NOERROR/NODATA or NXDOMAIN answers that need validation */
@@ -1991,7 +1994,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                iter_dns_store(qstate->env, &iq->response->qinfo,
                        iq->response->rep, 0, qstate->prefetch_leeway,
                        iq->dp&&iq->dp->has_parent_side_NS,
-                       qstate->region);
+                       qstate->region, qstate->query_flags);
                /* close down outstanding requests to be discarded */
                outbound_list_clear(&iq->outlist);
                iq->num_current_queries = 0;
@@ -2029,7 +2032,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                        /* Store the referral under the current query */
                        /* no prefetch-leeway, since its not the answer */
                        iter_dns_store(qstate->env, &iq->response->qinfo,
-                               iq->response->rep, 1, 0, 0, NULL);
+                               iq->response->rep, 1, 0, 0, NULL, 0);
                        if(iq->store_parent_NS)
                                iter_store_parentside_NS(qstate->env, 
                                        iq->response->rep);
@@ -2128,7 +2131,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                /* prefetchleeway applied because this updates answer parts */
                iter_dns_store(qstate->env, &iq->response->qinfo,
                        iq->response->rep, 1, qstate->prefetch_leeway,
-                       iq->dp&&iq->dp->has_parent_side_NS, NULL);
+                       iq->dp&&iq->dp->has_parent_side_NS, NULL,
+                       qstate->query_flags);
                /* set the current request's qname to the new value. */
                iq->qchase.qname = sname;
                iq->qchase.qname_len = snamelen;
@@ -2209,7 +2213,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
 }
 
 /**
- * Return priming query results to interestes super querystates.
+ * Return priming query results to interested super querystates.
  * 
  * Sets the delegation point and delegation message (not nonRD queries).
  * This is a callback from walk_supers.
@@ -2640,7 +2644,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
                        iter_dns_store(qstate->env, &qstate->qinfo, 
                                iq->response->rep, 0, qstate->prefetch_leeway,
                                iq->dp&&iq->dp->has_parent_side_NS,
-                               qstate->region);
+                               qstate->region, qstate->query_flags);
                }
        }
        qstate->return_rcode = LDNS_RCODE_NOERROR;
index 2f3848008e2753dec2f35ed48bf2b6f97c09505d..1091dcf1072774b9491a2c180b018b4e3343d544 100644 (file)
@@ -67,7 +67,7 @@ int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo, st
     }
 
     return dns_cache_store(qstate->env, qinfo, msgrep, is_referral, 
-       qstate->prefetch_leeway, 0, NULL);
+       qstate->prefetch_leeway, 0, NULL, qstate->query_flags);
 }
 
 /*  Invalidate the message associated with query_info stored in message cache */
@@ -78,7 +78,7 @@ void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qin
     struct reply_info *r;
     size_t i, j;
 
-    h = query_info_hash(qinfo);
+    h = query_info_hash(qinfo, qstate->query_flags);
     if ((e=slabhash_lookup(qstate->env->msg_cache, h, qinfo, 0))) 
     {
        r = (struct reply_info*)(e->data);
index c663b8e8b9a2aaccda0d60211c91958e75acb01f..4692744a15ddf5fd13fd1967b96942e4b843d732 100644 (file)
@@ -184,7 +184,7 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region,
 /** lookup message in message cache */
 static struct msgreply_entry* 
 msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen, 
-       uint16_t qtype, uint16_t qclass, time_t now, int wr)
+       uint16_t qtype, uint16_t qclass, uint16_t flags, time_t now, int wr)
 {
        struct lruhash_entry* e;
        struct query_info k;
@@ -194,7 +194,7 @@ msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen,
        k.qname_len = qnamelen;
        k.qtype = qtype;
        k.qclass = qclass;
-       h = query_info_hash(&k);
+       h = query_info_hash(&k, flags);
        e = slabhash_lookup(env->msg_cache, h, &k, wr);
 
        if(!e) return NULL;
@@ -226,8 +226,10 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
                                addr_to_additional(akey, region, *msg, now);
                        lock_rw_unlock(&akey->entry.lock);
                } else {
+                       /* BIT_CD on false because delegpt lookup does
+                        * not use dns64 translation */
                        neg = msg_cache_lookup(env, ns->name, ns->namelen,
-                               LDNS_RR_TYPE_A, qclass, now, 0);
+                               LDNS_RR_TYPE_A, qclass, 0, now, 0);
                        if(neg) {
                                delegpt_add_neg_msg(dp, neg);
                                lock_rw_unlock(&neg->entry.lock);
@@ -244,8 +246,10 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
                                addr_to_additional(akey, region, *msg, now);
                        lock_rw_unlock(&akey->entry.lock);
                } else {
+                       /* BIT_CD on false because delegpt lookup does
+                        * not use dns64 translation */
                        neg = msg_cache_lookup(env, ns->name, ns->namelen,
-                               LDNS_RR_TYPE_AAAA, qclass, now, 0);
+                               LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
                        if(neg) {
                                delegpt_add_neg_msg(dp, neg);
                                lock_rw_unlock(&neg->entry.lock);
@@ -276,8 +280,10 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
                                ns->name, LDNS_RR_TYPE_A, qclass);
                        lock_rw_unlock(&akey->entry.lock);
                } else {
+                       /* BIT_CD on false because delegpt lookup does
+                        * not use dns64 translation */
                        neg = msg_cache_lookup(env, ns->name, ns->namelen,
-                               LDNS_RR_TYPE_A, qclass, now, 0);
+                               LDNS_RR_TYPE_A, qclass, 0, now, 0);
                        if(neg) {
                                delegpt_add_neg_msg(dp, neg);
                                lock_rw_unlock(&neg->entry.lock);
@@ -294,8 +300,10 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
                                ns->name, LDNS_RR_TYPE_AAAA, qclass);
                        lock_rw_unlock(&akey->entry.lock);
                } else {
+                       /* BIT_CD on false because delegpt lookup does
+                        * not use dns64 translation */
                        neg = msg_cache_lookup(env, ns->name, ns->namelen,
-                               LDNS_RR_TYPE_AAAA, qclass, now, 0);
+                               LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
                        if(neg) {
                                delegpt_add_neg_msg(dp, neg);
                                lock_rw_unlock(&neg->entry.lock);
@@ -626,7 +634,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
 struct dns_msg* 
 dns_cache_lookup(struct module_env* env,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-       struct regional* region, struct regional* scratch)
+       uint16_t flags, struct regional* region, struct regional* scratch)
 {
        struct lruhash_entry* e;
        struct query_info k;
@@ -639,7 +647,7 @@ dns_cache_lookup(struct module_env* env,
        k.qname_len = qnamelen;
        k.qtype = qtype;
        k.qclass = qclass;
-       h = query_info_hash(&k);
+       h = query_info_hash(&k, flags);
        e = slabhash_lookup(env->msg_cache, h, &k, 0);
        if(e) {
                struct msgreply_entry* key = (struct msgreply_entry*)e->key;
@@ -716,7 +724,7 @@ dns_cache_lookup(struct module_env* env,
        if(env->cfg->harden_below_nxdomain)
            while(!dname_is_root(k.qname)) {
                dname_remove_label(&k.qname, &k.qname_len);
-               h = query_info_hash(&k);
+               h = query_info_hash(&k, flags);
                e = slabhash_lookup(env->msg_cache, h, &k, 0);
                if(e) {
                        struct reply_info* data = (struct reply_info*)e->data;
@@ -741,7 +749,7 @@ dns_cache_lookup(struct module_env* env,
 int 
 dns_cache_store(struct module_env* env, struct query_info* msgqinf,
         struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
-       struct regional* region)
+       struct regional* region, uint16_t flags)
 {
        struct reply_info* rep = NULL;
        /* alloc, malloc properly (not in region, like msg is) */
@@ -786,7 +794,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
                 * Not AA from cache. Not CD in cache (depends on client bit). */
                rep->flags |= (BIT_RA | BIT_QR);
                rep->flags &= ~(BIT_AA | BIT_CD);
-               h = query_info_hash(&qinf);
+               h = query_info_hash(&qinf, flags);
                dns_cache_store_msg(env, &qinf, h, rep, leeway, pside, msgrep,
                        region);
                /* qname is used inside query_info_entrysetup, and set to 
@@ -798,11 +806,11 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
 
 int 
 dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo,
-        time_t adjust)
+        time_t adjust, uint16_t flags)
 {
        struct msgreply_entry* msg;
        msg = msg_cache_lookup(env, qinfo->qname, qinfo->qname_len,
-               qinfo->qtype, qinfo->qclass, *env->now, 1);
+               qinfo->qtype, qinfo->qclass, flags, *env->now, 1);
        if(msg) {
                struct reply_info* rep = (struct reply_info*)msg->entry.data;
                if(rep) {
index 05a3e62965430ea3fde6deacd7779e40e22616ce..69796c2eb204c6f7e64b3b26dc06983feb2e7ecb 100644 (file)
@@ -79,11 +79,12 @@ struct dns_msg {
  *     can be updated to full TTL even in prefetch situations.
  * @param region: region to allocate better entries from cache into.
  *   (used when is_referral is false).
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
  * @return 0 on alloc error (out of memory).
  */
 int dns_cache_store(struct module_env* env, struct query_info* qinf,
         struct reply_info* rep, int is_referral, time_t leeway, int pside,
-       struct regional* region); 
+       struct regional* region, uint16_t flags); 
 
 /**
  * Store message in the cache. Stores in message cache and rrset cache.
@@ -132,6 +133,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
  * @param qnamelen: length of qname.
  * @param qtype: query type.
  * @param qclass: query class.
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
  * @param region: where to allocate result.
  * @param scratch: where to allocate temporary data.
  * @return new response message (alloced in region, rrsets do not have IDs).
@@ -140,7 +142,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
  */
 struct dns_msg* dns_cache_lookup(struct module_env* env,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-       struct regional* region, struct regional* scratch);
+       uint16_t flags, struct regional* region, struct regional* scratch);
 
 /** 
  * find and add A and AAAA records for missing nameservers in delegpt 
@@ -186,9 +188,10 @@ int dns_msg_authadd(struct dns_msg* msg, struct regional* region,
  * @param env: module environment with caches and time.
  * @param qinfo: query info for the query that needs adjustment.
  * @param adjust: time in seconds to add to the prefetch_leeway.
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
  * @return false if not in cache. true if added.
  */
 int dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo,
-        time_t adjust);
+        time_t adjust, uint16_t flags);
 
 #endif /* SERVICES_CACHE_DNS_H */
index bc711d9b3ed69619da8943b3362704ad0abbe121..780cb3e4df1bf627dd4f42b2b621ce5ac18a7816 100644 (file)
@@ -132,6 +132,11 @@ mesh_state_compare(const void* ap, const void* bp)
        if(!a->s.is_priming && b->s.is_priming)
                return 1;
 
+       if(a->s.is_valrec && !b->s.is_valrec)
+               return -1;
+       if(!a->s.is_valrec && b->s.is_valrec)
+               return 1;
+
        if((a->s.query_flags&BIT_RD) && !(b->s.query_flags&BIT_RD))
                return -1;
        if(!(a->s.query_flags&BIT_RD) && (b->s.query_flags&BIT_RD))
@@ -277,11 +282,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
         uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
         uint16_t qid)
 {
-       /* do not use CD flag from user for mesh state, we want the CD-query
-        * to receive validation anyway, to protect out cache contents and
-        * avoid bad-data in this cache that a downstream validator cannot
-        * remove from this cache */
-       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
        int was_detached = 0;
        int was_noreply = 0;
        int added = 0;
@@ -311,7 +312,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
 #ifdef UNBOUND_DEBUG
                struct rbnode_t* n;
 #endif
-               s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+               s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
                if(!s) {
                        log_err("mesh_state_create: out of memory; SERVFAIL");
                        error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
@@ -375,7 +376,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, 
        uint16_t qid, mesh_cb_func_t cb, void* cb_arg)
 {
-       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
        int was_detached = 0;
        int was_noreply = 0;
        int added = 0;
@@ -386,7 +387,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
 #ifdef UNBOUND_DEBUG
                struct rbnode_t* n;
 #endif
-               s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+               s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
                if(!s) {
                        return 0;
                }
@@ -428,7 +429,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
 void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
         uint16_t qflags, time_t leeway)
 {
-       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+       struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
 #ifdef UNBOUND_DEBUG
        struct rbnode_t* n;
 #endif
@@ -447,7 +448,7 @@ void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
                mesh->stats_dropped ++;
                return;
        }
-       s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+       s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
        if(!s) {
                log_err("prefetch mesh_state_create: out of memory");
                return;
@@ -496,7 +497,7 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
 
 struct mesh_state* 
 mesh_state_create(struct module_env* env, struct query_info* qinfo, 
-       uint16_t qflags, int prime)
+       uint16_t qflags, int prime, int valrec)
 {
        struct regional* region = alloc_reg_obtain(env->alloc);
        struct mesh_state* mstate;
@@ -533,6 +534,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
        /* remove all weird bits from qflags */
        mstate->s.query_flags = (qflags & (BIT_RD|BIT_CD));
        mstate->s.is_priming = prime;
+       mstate->s.is_valrec = valrec;
        mstate->s.reply = NULL;
        mstate->s.region = region;
        mstate->s.curmod = 0;
@@ -679,12 +681,14 @@ void mesh_detach_subs(struct module_qstate* qstate)
 }
 
 int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
-        uint16_t qflags, int prime, struct module_qstate** newq)
+        uint16_t qflags, int prime, int valrec, struct module_qstate** newq)
 {
        /* find it, if not, create it */
        struct mesh_area* mesh = qstate->env->mesh;
-       struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime);
+       struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime,
+               valrec);
        int was_detached;
+       log_info("mesh attach sub: myvalrec is %d", qstate->is_valrec);
        if(mesh_detect_cycle_found(qstate, sub)) {
                verbose(VERB_ALGO, "attach failed, cycle detected");
                return 0;
@@ -694,7 +698,8 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
                struct rbnode_t* n;
 #endif
                /* create a new one */
-               sub = mesh_state_create(qstate->env, qinfo, qflags, prime);
+               sub = mesh_state_create(qstate->env, qinfo, qflags, prime,
+                       valrec);
                if(!sub) {
                        log_err("mesh_attach_sub: out of memory");
                        return 0;
@@ -941,13 +946,14 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
 }
 
 struct mesh_state* mesh_area_find(struct mesh_area* mesh,
-       struct query_info* qinfo, uint16_t qflags, int prime)
+       struct query_info* qinfo, uint16_t qflags, int prime, int valrec)
 {
        struct mesh_state key;
        struct mesh_state* result;
 
        key.node.key = &key;
        key.s.is_priming = prime;
+       key.s.is_valrec = valrec;
        key.s.qinfo = *qinfo;
        key.s.query_flags = qflags;
        
@@ -1107,8 +1113,9 @@ mesh_log_list(struct mesh_area* mesh)
        struct mesh_state* m;
        int num = 0;
        RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
-               snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s%s", 
+               snprintf(buf, sizeof(buf), "%d%s%s%s%s%s%s mod%d %s%s", 
                        num++, (m->s.is_priming)?"p":"",  /* prime */
+                       (m->s.is_valrec)?"v":"",  /* prime */
                        (m->s.query_flags&BIT_RD)?"RD":"",
                        (m->s.query_flags&BIT_CD)?"CD":"",
                        (m->super_set.count==0)?"d":"", /* detached */
@@ -1178,10 +1185,11 @@ mesh_get_mem(struct mesh_area* mesh)
 
 int 
 mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
-       uint16_t flags, int prime)
+       uint16_t flags, int prime, int valrec)
 {
        struct mesh_area* mesh = qstate->env->mesh;
-       struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, flags, prime);
+       struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, flags, prime,
+               valrec);
        return mesh_detect_cycle_found(qstate, dep_m);
 }
 
index fbfbbcb4a94b93da621728d8ca2cec6faec89330..086e39094e8f9caed021fa4b8c470268cc5d8854 100644 (file)
@@ -353,12 +353,13 @@ void mesh_detach_subs(struct module_qstate* qstate);
  * @param qinfo: what to query for (copied).
  * @param qflags: what flags to use (RD / CD flag or not).
  * @param prime: if it is a (stub) priming query.
+ * @param valrec: if it is a validation recursion query (lookup of key, DS).
  * @param newq: If the new subquery needs initialisation, it is returned,
  *     otherwise NULL is returned.
  * @return: false on error, true if success (and init may be needed).
  */
 int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
-       uint16_t qflags, int prime, struct module_qstate** newq);
+       uint16_t qflags, int prime, int valrec, struct module_qstate** newq);
 
 /**
  * Query state is done, send messages to reply entries.
@@ -406,10 +407,12 @@ void mesh_state_delete(struct module_qstate* qstate);
  * @param qinfo: query info that the mesh is for.
  * @param qflags: flags for query (RD / CD flag).
  * @param prime: if true, it is a priming query, set is_priming on mesh state.
+ * @param valrec: if true, it is a validation recursion query, and sets
+ *     is_valrec on the mesh state.
  * @return: new mesh state or NULL on allocation error.
  */
 struct mesh_state* mesh_state_create(struct module_env* env, 
-       struct query_info* qinfo, uint16_t qflags, int prime);
+       struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
 
 /**
  * Cleanup a mesh state and its query state. Does not do rbtree or 
@@ -432,10 +435,11 @@ void mesh_delete_all(struct mesh_area* mesh);
  * @param qinfo: what query
  * @param qflags: if RD / CD bit is set or not.
  * @param prime: if it is a priming query.
+ * @param valrec: if it is a validation-recursion query.
  * @return: mesh state or NULL if not found.
  */
 struct mesh_state* mesh_area_find(struct mesh_area* mesh, 
-       struct query_info* qinfo, uint16_t qflags, int prime);
+       struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
 
 /**
  * Setup attachment super/sub relation between super and sub mesh state.
@@ -523,13 +527,14 @@ size_t mesh_get_mem(struct mesh_area* mesh);
  * @param qinfo: query info for dependency.
  * @param flags: query flags of dependency.
  * @param prime: if dependency is a priming query or not.
+ * @param valrec: if it is a validation recursion query (lookup of key, DS).
  * @return true if the name,type,class exists and the given qstate mesh exists
  *     as a dependency of that name. Thus if qstate becomes dependent on
  *     name,type,class then a cycle is created, this is return value 1.
  *     Too large to search is value 2 (also true).
  */
 int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
-       uint16_t flags, int prime);
+       uint16_t flags, int prime, int valrec);
 
 /** compare two mesh_states */
 int mesh_state_compare(const void* ap, const void* bp);
index 126e7bef45b7c5b0f12a345d1571aed3be9b1a61..0d2565753baf90c547d3449b5f3f03d5f5a367c1 100644 (file)
@@ -576,10 +576,12 @@ reply_info_delete(void* d, void* ATTR_UNUSED(arg))
 }
 
 hashvalue_t 
-query_info_hash(struct query_info *q)
+query_info_hash(struct query_info *q, uint16_t flags)
 {
        hashvalue_t h = 0xab;
        h = hashlittle(&q->qtype, sizeof(q->qtype), h);
+       if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
+               h++;
        h = hashlittle(&q->qclass, sizeof(q->qclass), h);
        h = dname_query_hash(q->qname, h);
        return h;
index ccbd0d7483819e1c6d5a9e672aa2022592f93249..e8d6d762e01af2c37a414f1193fe0715b91e513c 100644 (file)
@@ -305,8 +305,9 @@ void query_entry_delete(void *q, void* arg);
 /** delete reply_info data structure */
 void reply_info_delete(void* d, void* arg);
 
-/** calculate hash value of query_info, lowercases the qname */
-hashvalue_t query_info_hash(struct query_info *q);
+/** calculate hash value of query_info, lowercases the qname,
+ * uses CD flag for AAAA qtype */
+hashvalue_t query_info_hash(struct query_info *q, uint16_t flags);
 
 /**
  * Setup query info entry
index 3a5fc5f0611abc3b0582de4ae29fe2fc4ff1e50b..5a77432c775e51e486f33b8de74ea8ed9dd84caa 100644 (file)
@@ -280,7 +280,7 @@ fptr_whitelist_modenv_detach_subs(void (*fptr)(
 int 
 fptr_whitelist_modenv_attach_sub(int (*fptr)(
         struct module_qstate* qstate, struct query_info* qinfo,
-        uint16_t qflags, int prime, struct module_qstate** newq))
+        uint16_t qflags, int prime, int valrec, struct module_qstate** newq))
 {
        if(fptr == &mesh_attach_sub) return 1;
        return 0;
@@ -296,7 +296,7 @@ fptr_whitelist_modenv_kill_sub(void (*fptr)(struct module_qstate* newq))
 int 
 fptr_whitelist_modenv_detect_cycle(int (*fptr)(        
        struct module_qstate* qstate, struct query_info* qinfo,         
-       uint16_t flags, int prime))
+       uint16_t flags, int prime, int valrec))
 {
        if(fptr == &mesh_detect_cycle) return 1;
        return 0;
index 62692ba8b530f3522c55096a53993185247bebe1..10de5d8167726851531a74703e389a9b066b35fb 100644 (file)
@@ -233,7 +233,7 @@ int fptr_whitelist_modenv_detach_subs(void (*fptr)(
  */
 int fptr_whitelist_modenv_attach_sub(int (*fptr)(
        struct module_qstate* qstate, struct query_info* qinfo, 
-       uint16_t qflags, int prime, struct module_qstate** newq));
+       uint16_t qflags, int prime, int valrec, struct module_qstate** newq));
 
 /**
  * Check function pointer whitelist for module_env kill_sub callback values.
@@ -251,7 +251,7 @@ int fptr_whitelist_modenv_kill_sub(void (*fptr)(struct module_qstate* newq));
  */
 int fptr_whitelist_modenv_detect_cycle(int (*fptr)(
        struct module_qstate* qstate, struct query_info* qinfo, 
-       uint16_t flags, int prime));
+       uint16_t flags, int prime, int valrec));
 
 /**
  * Check function pointer whitelist for module init call values.
index f95ff6dc83729c58b273282930761a337723fdcc..b9dde36e2f3ce445f3588b8a26ba2281dff59a7a 100644 (file)
@@ -256,13 +256,14 @@ struct module_env {
         * @param qinfo: what to query for (copied).
         * @param qflags: what flags to use (RD, CD flag or not).
         * @param prime: if it is a (stub) priming query.
+        * @param valrec: validation lookup recursion, does not need validation
         * @param newq: If the new subquery needs initialisation, it is 
         *      returned, otherwise NULL is returned.
         * @return: false on error, true if success (and init may be needed).
         */ 
        int (*attach_sub)(struct module_qstate* qstate, 
                struct query_info* qinfo, uint16_t qflags, int prime, 
-               struct module_qstate** newq);
+               int valrec, struct module_qstate** newq);
 
        /**
         * Kill newly attached sub. If attach_sub returns newq for 
@@ -280,13 +281,15 @@ struct module_env {
         * @param qinfo: query info for dependency. 
         * @param flags: query flags of dependency, RD/CD flags.
         * @param prime: if dependency is a priming query or not.
+        * @param valrec: validation lookup recursion, does not need validation
         * @return true if the name,type,class exists and the given 
         *      qstate mesh exists as a dependency of that name. Thus 
         *      if qstate becomes dependent on name,type,class then a 
         *      cycle is created.
         */
        int (*detect_cycle)(struct module_qstate* qstate, 
-               struct query_info* qinfo, uint16_t flags, int prime);
+               struct query_info* qinfo, uint16_t flags, int prime,
+               int valrec);
 
        /** region for temporary usage. May be cleared after operate() call. */
        struct regional* scratch;
@@ -397,6 +400,9 @@ struct module_qstate {
        uint16_t query_flags;
        /** if this is a (stub or root) priming query (with hints) */
        int is_priming;
+       /** if this is a validation recursion query that does not get
+        * validation itself */
+       int is_valrec;
 
        /** comm_reply contains server replies */
        struct comm_reply* reply;
index aefa26a279486af755d83fae311ce46d5dee9c9d..1e929572f2557760f369cd55808fd51e0931c5f4 100644 (file)
@@ -289,6 +289,11 @@ needs_validation(struct module_qstate* qstate, int ret_rc,
                verbose(VERB_ALGO, "not validating response due to CD bit");
                return 0;
        }
+       if(qstate->is_valrec) {
+               verbose(VERB_ALGO, "not validating response, is valrec"
+                       "(validation recursion lookup)");
+               return 0;
+       }
 
        if(ret_rc != LDNS_RCODE_NOERROR || !ret_msg)
                rcode = ret_rc;
@@ -351,14 +356,20 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
        struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
        struct module_qstate* newq;
        struct query_info ask;
+       int valrec;
        ask.qname = name;
        ask.qname_len = namelen;
        ask.qtype = qtype;
        ask.qclass = qclass;
        log_query_info(VERB_ALGO, "generate request", &ask);
        fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
+       /* enable valrec flag to avoid recursion to the same validation
+        * routine, this lookup is simply a lookup. DLVs need validation */
+       if(qtype == LDNS_RR_TYPE_DLV)
+               valrec = 0;
+       else valrec = 1;
        if(!(*qstate->env->attach_sub)(qstate, &ask, 
-               (uint16_t)(BIT_RD|flags), 0, &newq)){
+               (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){
                log_err("Could not generate request: out of memory");
                return 0;
        }
@@ -2005,14 +2016,16 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
                /* if secure, this will override cache anyway, no need
                 * to check if from parentNS */
                if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, 
-                       vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL)) {
+                       vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL,
+                       qstate->query_flags)) {
                        log_err("out of memory caching validator results");
                }
        } else {
                /* for a referral, store the verified RRsets */
                /* and this does not get prefetched, so no leeway */
                if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, 
-                       vq->orig_msg->rep, 1, 0, 0, NULL)) {
+                       vq->orig_msg->rep, 1, 0, 0, NULL,
+                       qstate->query_flags)) {
                        log_err("out of memory caching validator results");
                }
        }