- fix to locate nameservers for DS lookup with NS fetches.

git-svn-id: file:///svn/unbound/trunk@2645 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2012-03-19 15:44:21 +00:00
parent d17f39416b
commit 0d5441bd8a
6 changed files with 302 additions and 0 deletions

View File

@ -1,5 +1,6 @@
19 March 2012: Wouter
- iana portlist updated.
- fix to locate nameservers for DS lookup with NS fetches.
16 March 2012: Wouter
- Patch for access to full DNS packet data in unbound python module

View File

@ -968,3 +968,35 @@ void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old)
a = a->next_usable;
}
}
int
iter_ds_toolow(struct dns_msg* msg)
{
/* if for query example.com, there is example.com SOA or a subdomain
* of example.com, then we are too low and need to fetch NS. */
size_t i = msg->rep->an_numrrsets;
for(; i < msg->rep->an_numrrsets + msg->rep->ns_numrrsets; i++) {
struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA &&
dname_subdomain_c(s->rk.dname, msg->qinfo.qname)) {
/* point is too low */
return 1;
}
}
return 0;
}
int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp)
{
/* no delegation point, do not see how we can go down,
* robust check, it should really exist */
if(!dp) return 0;
/* see if dp equals the qname, then we cannot go down further */
if(query_dname_compare(qinfo->qname, dp->name) == 0)
return 0;
/* if dp is one label above the name we also cannot go down further */
if(dname_count_labels(qinfo->qname) == dp->namelabs+1)
return 0;
return 1;
}

View File

@ -311,4 +311,21 @@ void iter_dec_attempts(struct delegpt* dp, int d);
*/
void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old);
/**
* See if a DS response (type ANSWER) is too low: a nodata answer with
* a SOA record in the authority section at-or-below the qchase.qname.
* @param msg: the response.
* @return true if too low.
*/
int iter_ds_toolow(struct dns_msg* msg);
/**
* See if delegpt can go down a step to the qname or not
* @param qinfo: the query name looked up.
* @param dp: checked if the name can go lower to the qname
* @return true if can go down, false if that would not be possible.
* the current response seems to be the one and only, best possible, response.
*/
int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp);
#endif /* ITERATOR_ITER_UTILS_H */

View File

@ -1526,6 +1526,60 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
/**
* Try to find the NS record set that will resolve a qtype DS query. Due
* to grandparent/grandchild reasons we did not get a proper lookup right
* away. We need to create type NS queries until we get the right parent
* for this lookup. We add labels to the delegation point - whose name is
* storage for where we are (with empty other content). Until we find an
* NS record, then we try the query again (which can result in doing this
* again). Or we go too low, it is not possible to resolve, servfail.
*
* @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
processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq,
int id)
{
int qlab = dname_count_labels(iq->qchase.qname);
struct module_qstate* subq = NULL;
verbose(VERB_ALGO, "processDSNSFind");
if(dname_subdomain_c(iq->dp->name, iq->qchase.qname) ||
qlab == iq->dp->namelabs+1)
/* we are too low - fail (robust check) */
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
/* dp is used for storage, this is our state */
log_assert(!iq->dp->dp_type_mlc); /* if malloced this would leak */
iq->dp->nslist = NULL;
iq->dp->target_list = NULL;
iq->dp->usable_list = NULL;
iq->dp->result_list = NULL;
iq->state = DSNS_FIND_STATE;
/* add one label to the dp */
iq->dp->name = iq->qchase.qname;
iq->dp->namelen = iq->qchase.qname_len;
/* we have qlab labels we want namelabs+1 labels */
dname_remove_labels(&iq->dp->name, &iq->dp->namelen,
qlab - (iq->dp->namelabs+1));
iq->dp->namelabs++;
/* spawn NS lookup (validation not needed, this is for DS lookup) */
log_nametypeclass(VERB_ALGO, "fetch nameservers",
iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) {
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
return 0;
}
/**
* This is the request event state where the request will be sent to one of
* its current query targets. This state also handles issuing target lookup
@ -1847,6 +1901,12 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
(iq->response->rep->an_numrrsets?"ANSWER":
"nodata ANSWER"));
}
/* if qtype is DS, check we have the right level of answer,
* like grandchild answer but we need the middle, reject it */
if(iq->qchase.qtype == LDNS_RR_TYPE_DS
&& iter_ds_toolow(iq->response)
&& iter_dp_cangodown(&iq->qchase, iq->dp))
return processDSNSFind(qstate, iq, id);
if(!iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
@ -2246,6 +2306,41 @@ processTargetResponse(struct module_qstate* qstate, int id,
}
}
/**
* Process response for DS NS Find queries, that attempt to find the delegation
* point where we ask the DS query from.
*
* @param qstate: query state.
* @param id: module id.
* @param forq: super query state.
*/
static void
processDSNSResponse(struct module_qstate* qstate, int id,
struct module_qstate* forq)
{
struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
/* if the finished (iq->response) query has no NS set: continue
* down to look for the right dp; nothing to change, do DPNSstate */
if(qstate->return_rcode != LDNS_RCODE_NOERROR)
return; /* seek further */
/* find the NS RRset (without allowing CNAMEs) */
if(!reply_find_rrset(qstate->return_msg->rep, qstate->qinfo.qname,
qstate->qinfo.qname_len, LDNS_RR_TYPE_NS,
qstate->qinfo.qclass)){
return; /* seek further */
}
/* else, store as DP and continue at querytargets */
foriq->state = QUERYTARGETS_STATE;
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
if(!foriq->dp) {
log_err("out of memory in dsns dp alloc");
return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */
}
/* success, go query the querytargets in the new dp (and go down) */
}
/**
* Process response for qclass=ANY queries for a particular class.
* Append to result or error-exit.
@ -2481,6 +2576,9 @@ iter_inform_super(struct module_qstate* qstate, int id,
{
if(!qstate->is_priming && super->qinfo.qclass == LDNS_RR_CLASS_ANY)
processClassResponse(qstate, id, super);
else if(super->qinfo.qtype == LDNS_RR_TYPE_DS && ((struct iter_qstate*)
super->minfo[id])->state == DSNS_FIND_STATE)
processDSNSResponse(qstate, id, super);
else if(qstate->return_rcode != LDNS_RCODE_NOERROR)
error_supers(qstate, id, super);
else if(qstate->is_priming)
@ -2530,6 +2628,9 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
case COLLECT_CLASS_STATE:
cont = processCollectClass(qstate, id);
break;
case DSNS_FIND_STATE:
cont = processDSNSFind(qstate, iq, id);
break;
case FINISHED_STATE:
cont = processFinished(qstate, iq, id);
break;
@ -2760,6 +2861,8 @@ iter_state_to_string(enum iter_state state)
return "PRIME RESPONSE STATE";
case COLLECT_CLASS_STATE :
return "COLLECT CLASS STATE";
case DSNS_FIND_STATE :
return "DSNS FIND STATE";
case QUERY_RESP_STATE :
return "QUERY RESPONSE STATE";
case FINISHED_STATE :

View File

@ -155,6 +155,10 @@ enum iter_state {
* it spawns off queries for every class, it returns here. */
COLLECT_CLASS_STATE,
/** Find NS record to resolve DS record from, walking to the right
* NS spot until we find it */
DSNS_FIND_STATE,
/** Responses that are to be returned upstream end at this state.
* As well as responses to target queries. */
FINISHED_STATE

145
testdata/iter_ds_locate_ns.rpl vendored Normal file
View File

@ -0,0 +1,145 @@
; config options
server:
target-fetch-policy: "0 0 0 0 0"
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test locate of NS records for parent nameservers of DS
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
; content of root-servers.net
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
root-servers.net. IN NS
SECTION ANSWER
root-servers.net. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
k.root-servers.net. IN A
SECTION ANSWER
K.ROOT-SERVERS.NET. IN A 193.0.14.129
SECTION AUTHORITY
root-servers.net. IN NS K.ROOT-SERVERS.NET.
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
k.root-servers.net. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
root-servers.net. IN SOA K.ROOT-SERVERS.NET. hostmaster. 1 2 3 4 5
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
root-servers.net. IN DS
SECTION ANSWER
SECTION AUTHORITY
root-servers.net. IN SOA K.ROOT-SERVERS.NET. hostmaster. 1 2 3 4 5
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
net. IN A
SECTION AUTHORITY
net. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
net. IN NS
SECTION ANSWER
net. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
root-servers.net. IN DS
SECTION AUTHORITY
net. IN SOA a.gtld-servers.net. hostmaster. 2 3 4 5 6
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
root-servers.net. IN A
SECTION AUTHORITY
root-servers.net. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
root-servers.net. IN DS
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
root-servers.net. IN DS
SECTION ANSWER
SECTION AUTHORITY
net. IN SOA a.gtld-servers.net. hostmaster. 2 3 4 5 6
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END