- sanitize incoming messages.
- split msgreply encode functions into own file msgencode.c.
- msg_parse to queryinfo/replyinfo conversion more versatile.
+ - process_response, classify response, delegpt_from_message.
31 May 2007: Wouter
- querytargets state.
*/
#include "config.h"
#include "iterator/iter_delegpt.h"
+#include "services/cache/dns.h"
#include "util/region-allocator.h"
#include "util/data/dname.h"
+#include "util/data/packed_rrset.h"
+#include "util/data/msgreply.h"
#include "util/net_help.h"
struct delegpt*
n++;
return n;
}
+
+/** find NS rrset in given list */
+static struct ub_packed_rrset_key*
+find_NS(struct reply_info* rep, size_t from, size_t to)
+{
+ size_t i;
+ for(i=from; i<to; i++) {
+ if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
+ return rep->rrsets[i];
+ }
+ return NULL;
+}
+
+struct delegpt*
+delegpt_from_message(struct dns_msg* msg, struct region* region)
+{
+ struct ub_packed_rrset_key* ns_rrset = NULL;
+ struct delegpt* dp;
+ size_t i;
+ /* look for NS records in the authority section... */
+ ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
+ msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
+
+ /* In some cases (even legitimate, perfectly legal cases), the
+ * NS set for the "referral" might be in the answer section. */
+ if(!ns_rrset)
+ ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
+
+ /* If there was no NS rrset in the authority section, then this
+ * wasn't a referral message. (It might not actually be a
+ * referral message anyway) */
+ if(!ns_rrset)
+ return NULL;
+
+ /* If we found any, then Yay! we have a delegation point. */
+ dp = delegpt_create(region);
+ if(!dp)
+ return NULL;
+ if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
+ return NULL;
+ if(!delegpt_rrset_add_ns(dp, region, ns_rrset))
+ return NULL;
+
+ /* add glue, A and AAAA in answer and additional section */
+ for(i=0; i<msg->rep->rrset_count; i++) {
+ struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
+ /* skip auth section. FIXME really needed?*/
+ if(msg->rep->an_numrrsets <= i &&
+ i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
+ continue;
+
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
+ if(!delegpt_add_rrset_A(dp, region, s))
+ return NULL;
+ } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
+ if(!delegpt_add_rrset_AAAA(dp, region, s))
+ return NULL;
+ }
+ }
+ return dp;
+}
+
+int
+delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
+ struct ub_packed_rrset_key* ns_rrset)
+{
+ struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
+ ns_rrset->entry.data;
+ size_t i;
+ for(i=0; i<nsdata->count; i++) {
+ if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
+ if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
+ (size_t)ldns_read_uint16(nsdata->rr_data[i])-2)
+ continue; /* bad format */
+ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
+ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2))
+ return 0;
+ }
+ return 1;
+}
+
+int
+delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
+ struct ub_packed_rrset_key* ak)
+{
+ struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
+ size_t i;
+ struct sockaddr_in sa;
+ socklen_t len = (socklen_t)sizeof(sa);
+ memset(&sa, 0, len);
+ sa.sin_family = AF_INET;
+ sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
+ for(i=0; i<d->count; i++) {
+ if(d->rr_len[i] != 2 + INET_SIZE)
+ continue;
+ memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
+ log_addr("adding A to deleg", (struct sockaddr_storage*)&sa,
+ len);
+ if(!delegpt_add_target(dp, region, ak->rk.dname,
+ ak->rk.dname_len, (struct sockaddr_storage*)&sa,
+ len))
+ return 0;
+ }
+ return 1;
+}
+
+int
+delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
+ struct ub_packed_rrset_key* ak)
+{
+ struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
+ size_t i;
+ struct sockaddr_in6 sa;
+ socklen_t len = (socklen_t)sizeof(sa);
+ memset(&sa, 0, len);
+ sa.sin6_family = AF_INET6;
+ sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
+ for(i=0; i<d->count; i++) {
+ if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */
+ continue;
+ memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
+ log_addr("adding AAAA to deleg", (struct sockaddr_storage*)&sa, len);
+ if(!delegpt_add_target(dp, region, ak->rk.dname,
+ ak->rk.dname_len, (struct sockaddr_storage*)&sa,
+ len))
+ return 0;
+ }
+ return 1;
+}
struct region;
struct delegpt_ns;
struct delegpt_addr;
+struct dns_msg;
+struct ub_packed_rrset_key;
/**
* Delegation Point.
*/
int delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name);
+/**
+ * Add NS rrset; calls add_ns repeatedly.
+ * @param dp: delegation point.
+ * @param region: where to allocate the info.
+ * @param ns_rrset: NS rrset.
+ * return 0 on alloc error.
+ */
+int delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
+ struct ub_packed_rrset_key* ns_rrset);
+
/**
* Add target address to the delegation point.
* @param dp: delegation point.
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
socklen_t addrlen);
+/**
+ * Add A RRset to delegpt.
+ * @param dp: delegation point.
+ * @param region: where to allocate the info.
+ * @param rrset: RRset A to add.
+ * @return 0 on alloc error.
+ */
+int delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
+ struct ub_packed_rrset_key* rrset);
+
+/**
+ * Add AAAA RRset to delegpt.
+ * @param dp: delegation point.
+ * @param region: where to allocate the info.
+ * @param rrset: RRset AAAA to add.
+ * @return 0 on alloc error.
+ */
+int delegpt_add_rrset_AAAA(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.
*/
size_t delegpt_count_missing_targets(struct delegpt* dp);
+/**
+ * Create new delegation point from a dns message
+ *
+ * Note that this method does not actually test to see if the message is an
+ * actual referral. It really is just checking to see if it can construct a
+ * delegation point, so the message could be of some other type (some ANSWER
+ * messages, some CNAME messages, generally.) Note that the resulting
+ * DelegationPoint will contain targets for all "relevant" glue (i.e.,
+ * address records whose ownernames match the target of one of the NS
+ * records), so if policy dictates that some glue should be discarded beyond
+ * that, discard it before calling this method. Note that this method will
+ * find "glue" in either the ADDITIONAL section or the ANSWER section.
+ *
+ * @param msg: the dns message, referral.
+ * @param region: where to allocate delegation point.
+ * @return new delegation point or NULL on alloc error, or if the
+ * message was not appropriate.
+ */
+struct delegpt* delegpt_from_message(struct dns_msg* msg,
+ struct region* region);
+
#endif /* ITERATOR_ITER_DELEGPT_H */
*/
#include "config.h"
#include "iterator/iter_resptype.h"
+#include "iterator/iter_delegpt.h"
#include "services/cache/dns.h"
#include "util/net_help.h"
#include "util/data/dname.h"
* messages, it can only be an ANSWER. */
return RESPONSE_TYPE_ANSWER;
}
+
+enum response_type
+response_type_from_server(struct dns_msg* msg, struct query_info* request,
+ struct delegpt* dp)
+{
+ uint8_t* origzone = (uint8_t*)"\000"; /* the default */
+ size_t origzonelen = 1;
+ size_t i;
+
+ if(!msg || !request)
+ return RESPONSE_TYPE_THROWAWAY;
+
+ /* If the message is NXDOMAIN, then it answers the question. */
+ if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN)
+ return RESPONSE_TYPE_ANSWER;
+
+ /* Other response codes mean (so far) to throw the response away as
+ * meaningless and move on to the next nameserver. */
+ if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NOERROR)
+ return RESPONSE_TYPE_THROWAWAY;
+
+ /* Note: TC bit has already been handled */
+
+ if(dp) {
+ origzone = dp->name;
+ origzonelen = dp->namelen;
+ }
+
+ /* First we look at the answer section. This can tell us if this is a
+ * CNAME or ANSWER or (provisional) ANSWER. */
+ if(msg->rep->an_numrrsets > 0) {
+ uint8_t* mname = request->qname;
+ size_t mname_len = request->qname_len;
+
+ /* Now look at the answer section first. 3 states: our
+ * answer is there directly, our answer is there after
+ * a cname, or there is just a cname. */
+ for(i=0; i<msg->rep->an_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
+
+ /* If we have encountered an answer (before or
+ * after a CNAME), then we are done! Note that
+ * if qtype == CNAME then this will be noted as an
+ * ANSWER before it gets treated as a CNAME, as
+ * it should. */
+ if(ntohs(s->rk.type) == request->qtype &&
+ ntohs(s->rk.rrset_class) == request->qclass &&
+ query_dname_compare(mname, s->rk.dname) == 0) {
+ if((msg->rep->flags&BIT_AA))
+ return RESPONSE_TYPE_ANSWER;
+ /* If the AA bit isn't on, and we've seen
+ * the answer, we only provisionally say
+ * 'ANSWER' -- it very well could be a
+ * REFERRAL. */
+ break;
+ }
+
+ /* If we have encountered a CNAME, make sure that
+ * it is relevant. */
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
+ query_dname_compare(mname, s->rk.dname) == 0) {
+ get_cname_target(s, &mname, &mname_len);
+ }
+ }
+ /* if we encountered a CNAME (or a bunch of CNAMEs), and
+ * still got to here, then it is a CNAME response.
+ * (This is regardless of the AA bit at this point) */
+ if(mname != request->qname) {
+ return RESPONSE_TYPE_CNAME;
+ }
+ }
+
+ /* Looking at the authority section, we just look and see if
+ * there is a delegation NS set, turning it into a delegation.
+ * Otherwise, we will have to conclude ANSWER (either it is
+ * NOERROR/NODATA, or an non-authoritative answer). */
+ for(i = msg->rep->an_numrrsets; i < (msg->rep->an_numrrsets +
+ msg->rep->ns_numrrsets); i++) {
+ struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
+
+ /* The normal way of detecting NOERROR/NODATA. */
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA &&
+ dname_subdomain_c(request->qname, s->rk.dname)) {
+ return RESPONSE_TYPE_ANSWER;
+ }
+
+ /* Detect REFERRAL/LAME/ANSWER based on the relationship
+ * of the NS set to the originating zone name. */
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS) {
+ /* If we are getting an NS set for the zone we
+ * thought we were contacting, then it is an answer.*/
+ /* FIXME: is this correct? */
+ if(query_dname_compare(s->rk.dname, origzone)) {
+ return RESPONSE_TYPE_ANSWER;
+ }
+ /* If we are getting a referral upwards (or to
+ * the same zone), then the server is 'lame'. */
+ if(dname_subdomain_c(origzone, s->rk.dname)) {
+ return RESPONSE_TYPE_LAME;
+ }
+ /* If the NS set is below the delegation point we
+ * are on, and it is non-authoritative, then it is
+ * a referral, otherwise it is an answer. */
+ if(dname_subdomain_c(s->rk.dname, origzone)) {
+ /* NOTE: I no longer remember in what case
+ * we would like this to be an answer.
+ * NODATA should have a SOA or nothing,
+ * not an NS rrset.
+ * True, referrals should not have the AA
+ * bit set, but... */
+
+ /* if((msg->rep->flags&BIT_AA))
+ return RESPONSE_TYPE_ANSWER; */
+ return RESPONSE_TYPE_REFERRAL;
+ }
+ /* Otherwise, the NS set is irrelevant. */
+ }
+ }
+
+ /* If we've gotten this far, this is NOERROR/NODATA (which could
+ * be an entirely empty message) */
+ return RESPONSE_TYPE_ANSWER;
+}
#define ITERATOR_ITER_RESPTYPE_H
struct dns_msg;
struct query_info;
+struct delegpt;
/**
* The response type is used to interpret the response.
enum response_type response_type_from_cache(struct dns_msg* msg,
struct query_info* request);
+/**
+ * Classifies a response message (from the wire) based on the current
+ * request.
+ *
+ * NOTE: currently this routine uses the AA bit in the response to help
+ * distinguish between some non-standard referrals and answers. It also
+ * relies somewhat on the originating zone to be accurate (for lameness
+ * detection, mostly).
+ *
+ * @param msg: the message from the cache.
+ * @param request: the request that generated the response.
+ * @param dp: The delegation point that was being queried
+ * when the response was returned.
+ * @return the response type (CNAME or ANSWER).
+ */
+enum response_type response_type_from_server(struct dns_msg* msg,
+ struct query_info* request, struct delegpt* dp);
+
#endif /* ITERATOR_ITER_RESPTYPE_H */
#include "iterator/iter_delegpt.h"
#include "services/cache/infra.h"
#include "services/cache/dns.h"
+#include "services/cache/rrset.h"
#include "util/net_help.h"
#include "util/module.h"
#include "util/log.h"
}
return m;
}
+
+int
+iter_dns_store(struct module_env* env, struct dns_msg* msg, int is_referral)
+{
+ struct reply_info* rep = NULL;
+ /* alloc, malloc properly (not in region, like msg is) */
+ rep = reply_info_copy(msg->rep, env->alloc);
+ if(!rep)
+ return 0;
+
+ if(is_referral) {
+ /* store rrsets */
+ struct rrset_ref ref;
+ uint32_t now = time(NULL);
+ size_t i;
+ reply_info_set_ttls(rep, now);
+ for(i=0; i<rep->rrset_count; i++) {
+ ref.key = rep->rrsets[i];
+ ref.id = rep->rrsets[i]->id;
+ /*ignore ret: it was in the cache, ref updated */
+ (void)rrset_cache_update(env->rrset_cache, &ref,
+ env->alloc, now);
+ }
+ return 1;
+ } else {
+ /* store msg, and rrsets */
+ struct query_info qinf;
+ hashvalue_t h;
+
+ qinf = msg->qinfo;
+ qinf.qname = memdup(msg->qinfo.qname, msg->qinfo.qname_len);
+ if(!qinf.qname)
+ return 0;
+ h = query_info_hash(&qinf);
+ dns_cache_store_msg(env, &qinf, h, rep);
+ free(qinf.qname);
+ }
+ return 1;
+}
struct dns_msg* dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg,
struct region* region);
+/**
+ * Allocate a dns_msg with malloc/alloc structure and store in dns cache.
+ * @param env: environment, with alloc structure and dns cache.
+ * @param msg: dns_msg from dns_alloc_msg for example.
+ * @param is_referral: If true, then the given message to be stored is a
+ * referral. The cache implementation may use this as a hint.
+ * @return 0 on alloc error (out of memory).
+ */
+int iter_dns_store(struct module_env* env, struct dns_msg* msg,
+ int is_referral);
+
#endif /* ITERATOR_ITER_UTILS_H */
return 0;
}
-#if 0
-/** TODO */
+/**
+ * Process the query response. All queries end up at this state first. This
+ * process generally consists of analyzing the response and routing the
+ * event to the next state (either bouncing it back to a request state, or
+ * terminating the processing for this event).
+ *
+ * @param qstate: query state.
+ * @param iq: iterator query state.
+ * @param id: module id.
+ * @return true if the event requires more immediate processing, false if
+ * not. This is generally only true when forwarding the request to
+ * the final state (i.e., on answer).
+ */
static int
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
- struct iter_env* ie, int id)
+ int id)
{
- return 0;
+ enum response_type type;
+ iq->num_current_queries--;
+ qstate->ext_state[id] = module_error; /* debug, must be overridden */
+ if(iq->response == NULL) {
+ verbose(VERB_ALGO, "query response was timeout");
+ return next_state(qstate, iq, QUERYTARGETS_STATE);
+ }
+ type = response_type_from_server(iq->response, &qstate->qinfo, iq->dp);
+ if(type == RESPONSE_TYPE_ANSWER) {
+ /* ANSWER type responses terminate the query algorithm,
+ * so they sent on their */
+ verbose(VERB_ALGO, "query response was ANSWER");
+
+ /* FIXME: there is a question about whether this gets
+ * stored under the original query or most recent query.
+ * The original query would reduce cache work, but you
+ * need to apply the prependList before caching, and
+ * also cache under the latest query. */
+ if(!iter_dns_store(qstate->env, iq->response, 0))
+ return error_response(qstate, iq, LDNS_RCODE_SERVFAIL);
+ /* close down outstanding requests to be discarded */
+ outbound_list_clear(&iq->outlist);
+ return final_state(qstate, iq);
+ } else if(type == RESPONSE_TYPE_REFERRAL) {
+ /* REFERRAL type responses get a reset of the
+ * delegation point, and back to the QUERYTARGETS_STATE. */
+ verbose(VERB_ALGO, "query response was REFERRAL");
+
+ /* Store the referral under the current query */
+ if(!iter_dns_store(qstate->env, iq->response, 1))
+ return error_response(qstate, iq, LDNS_RCODE_SERVFAIL);
+
+ /* Reset the event state, setting the current delegation
+ * point to the referral. */
+ iq->deleg_msg = iq->response;
+ iq->dp = delegpt_from_message(iq->response, qstate->region);
+ if(!iq->dp)
+ return error_response(qstate, iq, LDNS_RCODE_SERVFAIL);
+ iq->num_current_queries = 0;
+ iq->num_target_queries = -1;
+ /* Count this as a referral. */
+ iq->referral_count++;
+
+ /* stop current outstanding queries.
+ * FIXME: should the outstanding queries be waited for and
+ * handled?
+ */
+ outbound_list_clear(&iq->outlist);
+ verbose(VERB_ALGO, "cleared outbound list for next round");
+ return next_state(qstate, iq, QUERYTARGETS_STATE);
+ } else if(type == RESPONSE_TYPE_CNAME) {
+ uint8_t* sname = NULL;
+ size_t snamelen = 0;
+ /* CNAME type responses get a query restart (i.e., get a
+ * reset of the query state and go back to INIT_REQUEST_STATE).
+ */
+ verbose(VERB_ALGO, "query response was CNAME");
+ /* Process the CNAME response. */
+ if(!iq->orig_qname) {
+ iq->orig_qname = qstate->qinfo.qname;
+ iq->orig_qnamelen = qstate->qinfo.qname_len;
+ }
+ if(!handle_cname_response(qstate, iq, iq->response,
+ &sname, &snamelen))
+ return error_response(qstate, iq, LDNS_RCODE_SERVFAIL);
+ /* cache the CNAME response under the current query */
+ if(!iter_dns_store(qstate->env, iq->response, 0))
+ return error_response(qstate, iq, LDNS_RCODE_SERVFAIL);
+ /* set the current request's qname to the new value. */
+ qstate->qinfo.qname = sname;
+ qstate->qinfo.qname_len = snamelen;
+ /* Clear the query state, since this is a query restart. */
+ iq->deleg_msg = NULL;
+ iq->dp = NULL;
+ iq->num_current_queries = 0;
+ iq->num_target_queries = -1;
+ /* Note the query restart. */
+ iq->query_restart_count++;
+
+ /* stop current outstanding queries.
+ * FIXME: should the outstanding queries be waited for and
+ * handled?
+ */
+ outbound_list_clear(&iq->outlist);
+ verbose(VERB_ALGO, "cleared outbound list for query restart");
+ /* go to INIT_REQUEST_STATE for new qname. */
+ return next_state(qstate, iq, INIT_REQUEST_STATE);
+ } else if(type == RESPONSE_TYPE_LAME) {
+ /* Cache the LAMEness. */
+ /* TODO mark addr, dp->name, as lame */
+ verbose(VERB_ALGO, "query response was LAME");
+ } else if(type == RESPONSE_TYPE_THROWAWAY) {
+ /* LAME and THROWAWAY responses are handled the same way.
+ * In this case, the event is just sent directly back to
+ * the QUERYTARGETS_STATE without resetting anything,
+ * because, clearly, the next target must be tried. */
+ verbose(VERB_ALGO, "query response was THROWAWAY");
+ } else {
+ log_warn("A query response came back with an unknown type: %d",
+ (int)type);
+ }
+
+ /* LAME, THROWAWAY and "unknown" all end up here.
+ * Recycle to the QUERYTARGETS state to hopefully try a
+ * different target. */
+ return next_state(qstate, iq, QUERYTARGETS_STATE);
}
+#if 0
/** TODO */
static int
processPrimeResponse(struct module_qstate* qstate, struct iter_qstate* iq,
case QUERYTARGETS_STATE:
cont = processQueryTargets(qstate, iq, ie, id);
break;
-#if 0
case QUERY_RESP_STATE:
- cont = processQueryResponse(qstate, iq, ie, id);
+ cont = processQueryResponse(qstate, iq, id);
break;
+#if 0
case PRIME_RESP_STATE:
cont = processPrimeResponse(qstate, iq, ie, id);
break;
}
}
-/** add A records to delegation */
-static int
-add_a(struct ub_packed_rrset_key* ak, struct delegpt* dp,
- struct region* region, struct dns_msg** msg, uint32_t now)
-{
- struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
- size_t i;
- struct sockaddr_in sa;
- socklen_t len = (socklen_t)sizeof(sa);
- memset(&sa, 0, len);
- sa.sin_family = AF_INET;
- sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
- for(i=0; i<d->count; i++) {
- if(d->rr_len[i] != 2 + INET_SIZE)
- continue;
- memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
- log_addr("adding A to deleg", (struct sockaddr_storage*)&sa,
- len);
- if(!delegpt_add_target(dp, region, ak->rk.dname,
- ak->rk.dname_len, (struct sockaddr_storage*)&sa,
- len))
- return 0;
- }
- if(msg)
- addr_to_additional(ak, region, *msg, now);
- return 1;
-}
-
-/** add AAAA records to delegation */
-static int
-add_aaaa(struct ub_packed_rrset_key* ak, struct delegpt* dp,
- struct region* region, struct dns_msg** msg, uint32_t now)
-{
- struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
- size_t i;
- struct sockaddr_in6 sa;
- socklen_t len = (socklen_t)sizeof(sa);
- memset(&sa, 0, len);
- sa.sin6_family = AF_INET6;
- sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
- for(i=0; i<d->count; i++) {
- if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */
- continue;
- memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
- log_addr("adding AAAA to deleg", (struct sockaddr_storage*)&sa,
- len);
- if(!delegpt_add_target(dp, region, ak->rk.dname,
- ak->rk.dname_len, (struct sockaddr_storage*)&sa,
- len))
- return 0;
- }
- if(msg)
- addr_to_additional(ak, region, *msg, now);
- return 1;
-}
-
/** find and add A and AAAA records for nameservers in delegpt */
static int
find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region,
akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(akey) {
- if(!add_a(akey, dp, region, msg, now)) {
+ if(!delegpt_add_rrset_A(dp, region, akey)) {
lock_rw_unlock(&akey->entry.lock);
return 0;
}
+ if(msg)
+ addr_to_additional(akey, region, *msg, now);
lock_rw_unlock(&akey->entry.lock);
}
akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
if(akey) {
- if(!add_aaaa(akey, dp, region, msg, now)) {
+ if(!delegpt_add_rrset_AAAA(dp, region, akey)) {
lock_rw_unlock(&akey->entry.lock);
return 0;
}
+ if(msg)
+ addr_to_additional(akey, region, *msg, now);
lock_rw_unlock(&akey->entry.lock);
}
}
return 1;
}
-/** Add NS records to delegation */
-static void
-add_ns(struct packed_rrset_data* nsdata, struct delegpt* dp,
- struct region* region)
-{
- size_t i;
- for(i=0; i<nsdata->count; i++) {
- if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
- if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
- (size_t)ldns_read_uint16(nsdata->rr_data[i])-2)
- continue; /* bad format */
- /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
- if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2))
- log_err("find_delegation: addns out of memory");
- }
-}
-
/** find and add DS or NSEC to delegation msg */
static void
find_add_ds(struct module_env* env, struct region* region,
return NULL;
}
}
- add_ns(nsdata, dp, region);
+ if(!delegpt_rrset_add_ns(dp, region, nskey))
+ log_err("find_delegation: addns out of memory");
lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/
/* find and add DS/NSEC (if any) */
if(msg)
q->qname = NULL;
return e;
}
+
+static struct reply_info*
+copy_repinfo(struct reply_info* from)
+{
+ struct reply_info* cp;
+ /* rrset_count-1 because the first ref is part of the struct. */
+ size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
+ sizeof(struct ub_packed_rrset_key*) * from->rrset_count;
+ cp = (struct reply_info*)malloc(s +
+ sizeof(struct rrset_ref) * (from->rrset_count));
+ if(!cp) return NULL;
+ cp->flags = from->flags;
+ cp->qdcount = from->qdcount;
+ cp->ttl = from->ttl;
+ cp->an_numrrsets = from->an_numrrsets;
+ cp->ns_numrrsets = from->ns_numrrsets;
+ cp->ar_numrrsets = from->ar_numrrsets;
+ cp->rrset_count = from->rrset_count;
+ /* array starts after the refs */
+ cp->rrsets = (struct ub_packed_rrset_key**)
+ &(cp->ref[from->rrset_count]);
+ /* zero the arrays to assist cleanup in case of malloc failure */
+ memset( cp->rrsets, 0,
+ sizeof(struct ub_packed_rrset_key*) * from->rrset_count);
+ memset( &cp->ref[0], 0,
+ sizeof(struct rrset_ref) * from->rrset_count);
+ return cp;
+}
+
+struct reply_info*
+reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc)
+{
+ struct reply_info* cp;
+ if(!(cp = copy_repinfo(rep)))
+ return NULL;
+ /* TODO copy rrsets */
+ return cp;
+}
struct msgreply_entry* query_info_entrysetup(struct query_info* q,
struct reply_info* r, hashvalue_t h);
+/**
+ * Copy reply_info and all rrsets in it and allocate.
+ * @param rep: what to copy, probably inside region, no ref[] array in it.
+ * @param alloc: how to allocate rrset keys.
+ * @return new reply info or NULL on memory error.
+ */
+struct reply_info* reply_info_copy(struct reply_info* rep,
+ struct alloc_cache* alloc);
+
#endif /* UTIL_DATA_MSGREPLY_H */