- 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
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;
}
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;
+}
+
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.
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.
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,
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;
#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"
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 */
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) {
}
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;
+}
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 */
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)