From: Wouter Wijngaards Date: Mon, 4 Jun 2007 13:53:01 +0000 (+0000) Subject: Process target responses, case preservation. X-Git-Tag: release-0.4~101 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5eef2381f0c7c0fdc9bc913c9ed520f788de66aa;p=thirdparty%2Funbound.git Process target responses, case preservation. git-svn-id: file:///svn/unbound/trunk@365 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 66d9be2b9..43df54830 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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 diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index f7742702b..d06293fe2 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -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; +} + diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index 2c3b60058..174ccc2eb 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -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. diff --git a/iterator/iterator.c b/iterator/iterator.c index 3e289e88c..ab18c8ff1 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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; diff --git a/services/cache/infra.c b/services/cache/infra.c index 8a4a723d1..0a73f457e 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -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 */ diff --git a/services/outside_network.c b/services/outside_network.c index cf5ae88f4..b9a8bf9b0 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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) { diff --git a/util/data/msgreply.c b/util/data/msgreply.c index f589f0926..5c8a43b5c 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -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; ian_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; +} diff --git a/util/data/msgreply.h b/util/data/msgreply.h index a74f0fa00..075180469 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -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 */ diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index e7d172152..1f2805764 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -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)