process_response, classify response, delegpt_from_message.

git-svn-id: file:///svn/unbound/trunk@359 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-06-01 20:24:33 +00:00
parent a84ed747dc
commit a5e722d85f
11 changed files with 558 additions and 82 deletions

View file

@ -4,6 +4,7 @@
- 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.

View file

@ -41,8 +41,11 @@
*/
#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*
@ -188,3 +191,132 @@ delegpt_count_missing_targets(struct delegpt* dp)
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;
}

View file

@ -45,6 +45,8 @@
struct region;
struct delegpt_ns;
struct delegpt_addr;
struct dns_msg;
struct ub_packed_rrset_key;
/**
* Delegation Point.
@ -136,6 +138,16 @@ int delegpt_set_name(struct delegpt* dp, struct region* region, uint8_t* name);
*/
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.
@ -151,6 +163,26 @@ int delegpt_add_target(struct delegpt* dp, struct region* region,
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.
@ -181,4 +213,25 @@ void delegpt_add_unused_targets(struct delegpt* dp);
*/
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 */

View file

@ -41,6 +41,7 @@
*/
#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"
@ -97,3 +98,126 @@ response_type_from_cache(struct dns_msg* msg,
* 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;
}

View file

@ -44,6 +44,7 @@
#define ITERATOR_ITER_RESPTYPE_H
struct dns_msg;
struct query_info;
struct delegpt;
/**
* The response type is used to interpret the response.
@ -97,4 +98,22 @@ enum response_type {
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 */

View file

@ -46,6 +46,7 @@
#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"
@ -168,3 +169,42 @@ dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg, struct region* region)
}
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;
}

View file

@ -86,4 +86,15 @@ struct delegpt_addr* iter_server_selection(struct iter_env* iter_env,
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 */

View file

@ -1067,15 +1067,132 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
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,
@ -1134,10 +1251,10 @@ iter_handle(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;

84
services/cache/dns.c vendored
View file

@ -165,62 +165,6 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct region* region,
}
}
/** 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,
@ -232,42 +176,29 @@ 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,
@ -372,7 +303,8 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
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)

View file

@ -554,3 +554,41 @@ query_info_entrysetup(struct query_info* q, struct reply_info* r,
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;
}

View file

@ -276,4 +276,13 @@ hashvalue_t query_info_hash(struct query_info *q);
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 */