]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Process target responses, case preservation.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 4 Jun 2007 13:53:01 +0000 (13:53 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 4 Jun 2007 13:53:01 +0000 (13:53 +0000)
git-svn-id: file:///svn/unbound/trunk@365 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
iterator/iter_delegpt.c
iterator/iter_delegpt.h
iterator/iterator.c
services/cache/infra.c
services/outside_network.c
util/data/msgreply.c
util/data/msgreply.h
util/data/packed_rrset.c

index 66d9be2b93626a5833859e53ad2096b9541ac350..43df54830edc6e312a2871d48afbb7f718ff1e35 100644 (file)
@@ -5,6 +5,8 @@
        - do not touch qstate after worker_process_query because it may have
          been deleted by that routine.
        - Prime response state.
+       - Process target response state.
+       - some memcmp changed to dname_compare for case preservation.
 
 1 June 2007: Wouter
        - normalize incoming messages. Like unbound-java, with CNAME chain
index f7742702b66a9d203f2f4d84cb1f4b4322608b91..d06293fe26e0f6d0ac176c7e2159edb3b16653d8 100644 (file)
@@ -102,14 +102,13 @@ delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name)
        return 1;
 }
 
-/** find name in deleg list */
-static struct delegpt_ns*
+struct delegpt_ns*
 delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen)
 {
        struct delegpt_ns* p = dp->nslist;
        while(p) {
                if(namelen == p->namelen && 
-                       memcmp(name, p->name, namelen) == 0) {
+                       query_dname_compare(name, p->name) == 0) {
                        return p;
                }
                p = p->next;
@@ -320,3 +319,20 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
         }
         return 1;
 }
+
+int 
+delegpt_add_rrset(struct delegpt* dp, struct region* region,
+        struct ub_packed_rrset_key* rrset)
+{
+       if(!rrset)
+               return 1;
+       if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
+               return delegpt_rrset_add_ns(dp, region, rrset);
+       else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
+               return delegpt_add_rrset_A(dp, region, rrset);
+       else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
+               return delegpt_add_rrset_AAAA(dp, region, rrset);
+       log_warn("Unknown rrset type added to delegpt");
+       return 1;
+}
+
index 2c3b60058ec06e7f19ea81190372c8248f7db42f..174ccc2ebe8e8bdcd7b2e113ca597c5e76c58ad1 100644 (file)
@@ -183,6 +183,16 @@ int delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
 int delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region, 
        struct ub_packed_rrset_key* rrset);
 
+/**
+ * Add any RRset to delegpt.
+ * @param dp: delegation point.
+ * @param region: where to allocate the info.
+ * @param rrset: RRset to add, NS, A, AAAA.
+ * @return 0 on alloc error.
+ */
+int delegpt_add_rrset(struct delegpt* dp, struct region* region, 
+       struct ub_packed_rrset_key* rrset);
+
 /**
  * Add address to the delegation point. No servername is associated or checked.
  * @param dp: delegation point.
@@ -194,6 +204,16 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
 int delegpt_add_addr(struct delegpt* dp, struct region* region, 
        struct sockaddr_storage* addr, socklen_t addrlen);
 
+/** 
+ * Find NS record in name list of delegation point.
+ * @param dp: delegation point.
+ * @param name: name of nameserver to look for, uncompressed wireformat.
+ * @param namelen: length of name.
+ * @return the ns structure or NULL if not found.
+ */
+struct delegpt_ns* delegpt_find_ns(struct delegpt* dp, uint8_t* name, 
+       size_t namelen);
+
 /**
  * Print the delegation point to the log. For debugging.
  * @param dp: delegation point.
index 3e289e88c69285f503d7bdfc23ce374891e1f32f..ab18c8ff17bee6d30521de81d9ba4848b54ed4f1 100644 (file)
@@ -1257,15 +1257,76 @@ processPrimeResponse(struct module_qstate* qstate, struct iter_qstate* iq,
        return 0;
 }
 
-#if 0
-/** TODO */
+/** 
+ * Do final processing on responses to target queries. Events reach this
+ * state after the iterative resolution algorithm terminates. This state is
+ * responsible for reactiving the original event, and housekeeping related
+ * to received target responses (caching, updating the current delegation
+ * point, etc).
+ *
+ * @param qstate: query state.
+ * @param iq: iterator query state.
+ * @param id: module id.
+ * @return true if the event requires more (response) processing
+ *         immediately, false if not. This particular state always returns
+ *         false.
+ */
 static int
 processTargetResponse(struct module_qstate* qstate, struct iter_qstate* iq,
-       struct iter_env* ie, int id)
+       int id)
 {
+       struct ub_packed_rrset_key* rrset;
+       struct delegpt_ns* dpns;
+       struct module_qstate* forq = qstate->parent;
+       struct iter_qstate* foriq;
+       log_assert(qstate->parent); /* fetch targets for a parent */
+       foriq = (struct iter_qstate*)forq->minfo[id];
+       qstate->ext_state[id] = module_finished;
+
+       /* check to see if parent event is still interested.  */
+       if(iq->orig_qname)
+               dpns = delegpt_find_ns(foriq->dp, iq->orig_qname, 
+                       iq->orig_qnamelen);
+       else    dpns = delegpt_find_ns(foriq->dp, qstate->qinfo.qname,
+                       qstate->qinfo.qname_len);
+       if(!dpns) {
+               /* FIXME: maybe store this nameserver address in the cache
+                * anyways? */
+               /* If not, just stop processing this event */
+               return 0;
+       }
+
+       /* Tell the originating event that this target query has finished
+        * (regardless if it succeeded or not). */
+       foriq->num_target_queries--;
+
+       /* This response is relevant to the current query, so we 
+        * add (attempt to add, anyway) this target(s) and reactivate 
+        * the original event. 
+        * NOTE: we could only look for the AnswerRRset if the 
+        * response type was ANSWER. */
+       rrset = reply_find_answer_rrset(&qstate->qinfo, iq->response->rep);
+       if(rrset) {
+               /* if CNAMEs have been followed - add new NS to delegpt. */
+               if(!delegpt_find_ns(foriq->dp, rrset->rk.dname, 
+                       rrset->rk.dname_len)) {
+                       if(!delegpt_add_ns(foriq->dp, forq->region, 
+                               rrset->rk.dname))
+                               log_err("out of memory adding cnamed-ns");
+               }
+               if(!delegpt_add_rrset(foriq->dp, forq->region, rrset))
+                       log_err("out of memory adding targets");
+       } else  dpns->resolved = 1; /* fail the target */
+
+       log_assert(dpns->resolved); /* one way or another it is now done */
+
+       /* Reactivate the forEvent, now that it has either a new target or a
+        * failed target. */
+       foriq->state = QUERYTARGETS_STATE;
        return 0;
 }
 
+#if 0
 /** TODO */
 static int
 processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
@@ -1314,10 +1375,10 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
                        case PRIME_RESP_STATE:
                                cont = processPrimeResponse(qstate, iq, id);
                                break;
-#if 0
                        case TARGET_RESP_STATE:
-                               cont = processTargetResponse(qstate, iq, ie, id);
+                               cont = processTargetResponse(qstate, iq, id);
                                break;
+#if 0
                        case FINISHED_STATE:
                                cont = processFinished(qstate, iq, ie, id);
                                break;
index 8a4a723d1f597b39ce0e2c4d2033db534c6abce4..0a73f457ef6c24e9a3f9b4438b02f5f5e81448cd 100644 (file)
@@ -42,6 +42,7 @@
 #include "services/cache/infra.h"
 #include "util/storage/slabhash.h"
 #include "util/storage/lookup3.h"
+#include "util/data/dname.h"
 #include "util/log.h"
 #include "util/net_help.h"
 #include "util/config_file.h"
@@ -312,7 +313,7 @@ infra_lame_compfunc(void* key1, void* key2)
                        return -1;
                return 1;
        }
-       return memcmp(k1->zonename, k2->zonename, k1->namelen);
+       return query_dname_compare(k1->zonename, k2->zonename);
 }
 
 /** free key, lock and zonename */
index cf5ae88f4e06ddeefb0da00f13ad3d1b4a5aaceb..b9a8bf9b05452dcc63c01a81b328e0588c02eeb2 100644 (file)
@@ -138,6 +138,7 @@ serviced_cmp(const void* key1, const void* key2)
        if(q1->qbuflen > q2->qbuflen)
                return 1;
        log_assert(q1->qbuflen == q2->qbuflen);
+       /* FIXME: will not detect alternate casing of qname */
        if((r = memcmp(q1->qbuf, q2->qbuf, q1->qbuflen)) != 0)
                return r;
        if(q1->dnssec != q2->dnssec) {
index f589f09265671c8772ef54a935166325d6ec8da2..5c8a43b5c4780f1e27db68ecba7c07e6021baff6 100644 (file)
@@ -625,3 +625,29 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
        }
        return cp;
 }
+
+struct ub_packed_rrset_key* 
+reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
+{
+       uint8_t* sname = qinfo->qname;
+       size_t snamelen = qinfo->qname_len;
+       size_t i;
+       for(i=0; i<rep->an_numrrsets; i++) {
+               struct ub_packed_rrset_key* s = rep->rrsets[i];
+               /* first match type, for query of qtype cname */
+               if(ntohs(s->rk.type) == qinfo->qtype && 
+                       ntohs(s->rk.rrset_class) == qinfo->qclass && 
+                       snamelen == s->rk.dname_len &&
+                       query_dname_compare(sname, s->rk.dname) == 0) {
+                       return s;
+               }
+               /* follow CNAME chain (if any) */
+               if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 
+                       ntohs(s->rk.rrset_class) == qinfo->qclass && 
+                       snamelen == s->rk.dname_len &&
+                       query_dname_compare(sname, s->rk.dname) == 0) {
+                       get_cname_target(s, &sname, &snamelen);
+               }
+       }
+       return NULL;
+}
index a74f0fa00de6e591f420c073bfc110b7e72ac6b1..07518046995672561fcf8a41b247726c85caffa2 100644 (file)
@@ -290,4 +290,14 @@ struct msgreply_entry* query_info_entrysetup(struct query_info* q,
 struct reply_info* reply_info_copy(struct reply_info* rep, 
        struct alloc_cache* alloc, struct region* region);
 
+/**
+ * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the
+ * result may have a different owner name.
+ * @param qinfo: what to look for.
+ * @param rep: looks in answer section of this message.
+ * @return: pointer to rrset, or NULL if not found.
+ */
+struct ub_packed_rrset_key* reply_find_answer_rrset(struct query_info* qinfo,
+       struct reply_info* rep);
+
 #endif /* UTIL_DATA_MSGREPLY_H */
index e7d172152ffd6480ca08fcf88e9408907a667e18..1f2805764abecc310eb99573f45602403516335b 100644 (file)
@@ -105,7 +105,7 @@ ub_rrset_compare(void* k1, void* k2)
                        return -1;
                return 1;
        }
-       if((c=memcmp(key1->rk.dname, key2->rk.dname, key1->rk.dname_len)) != 0)
+       if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
                return c;
        if(key1->rk.rrset_class != key2->rk.rrset_class) {
                if(key1->rk.rrset_class < key2->rk.rrset_class)