mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 14:53:15 -05:00
Answer qclass=ANY.
git-svn-id: file:///svn/unbound/trunk@1938 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
72926a9f8c
commit
ab9bd76768
13 changed files with 494 additions and 3 deletions
|
|
@ -1,3 +1,7 @@
|
|||
15 December 2009: Wouter
|
||||
- Answer to qclass=ANY queries, with class IN contents.
|
||||
Test that validation also works.
|
||||
|
||||
11 December 2009: Wouter
|
||||
- on IPv4 UDP turn off DF flag.
|
||||
|
||||
|
|
|
|||
|
|
@ -353,6 +353,56 @@ forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass)
|
|||
return forwards_lookup(fwd, &root, qclass);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
rbnode_t* n;
|
||||
struct iter_forward_zone* p;
|
||||
if(*dclass == 0) {
|
||||
/* first root item is first item in tree */
|
||||
n = rbtree_first(fwd->tree);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0;
|
||||
p = (struct iter_forward_zone*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* root not first item? search for higher items */
|
||||
*dclass = p->dclass + 1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
}
|
||||
/* find class n in tree, we may get a direct hit, or if we don't
|
||||
* this is the last item of the previous class so rbtree_next() takes
|
||||
* us to the next root (if any) */
|
||||
key.node.key = &key;
|
||||
key.name = (uint8_t*)"\000";
|
||||
key.namelen = 1;
|
||||
key.namelabs = 0;
|
||||
key.dclass = *dclass;
|
||||
n = NULL;
|
||||
if(rbtree_find_less_equal(fwd->tree, &key, &n)) {
|
||||
/* exact */
|
||||
return 1;
|
||||
} else {
|
||||
/* smaller element */
|
||||
if(!n || n == RBTREE_NULL)
|
||||
return 0; /* nothing found */
|
||||
n = rbtree_next(n);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0; /* no higher */
|
||||
p = (struct iter_forward_zone*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* not a root node, return next higher item */
|
||||
*dclass = p->dclass+1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
forwards_get_mem(struct iter_forwards* fwd)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ struct iter_forwards {
|
|||
struct regional* region;
|
||||
/**
|
||||
* Zones are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qtype. Then on dname in nsec-like order, so that
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
* a lookup on class, name will return an exact match or the closest
|
||||
* match which gives the ancestor needed.
|
||||
* contents of type iter_forward_zone.
|
||||
|
|
@ -128,6 +128,14 @@ struct delegpt* forwards_lookup(struct iter_forwards* fwd,
|
|||
struct delegpt* forwards_lookup_root(struct iter_forwards* fwd,
|
||||
uint16_t qclass);
|
||||
|
||||
/**
|
||||
* Find next root item in forwards lookup tree.
|
||||
* @param fwd: the forward storage
|
||||
* @param qclass: class to look at next, or higher.
|
||||
* @return false if none found, or if true stored in qclass.
|
||||
*/
|
||||
int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass);
|
||||
|
||||
/**
|
||||
* Get memory in use by forward storage
|
||||
* @param fwd: forward storage.
|
||||
|
|
|
|||
|
|
@ -462,6 +462,11 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass)
|
||||
{
|
||||
return name_tree_next_root(&hints->tree, qclass);
|
||||
}
|
||||
|
||||
size_t
|
||||
hints_get_mem(struct iter_hints* hints)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ struct iter_hints {
|
|||
struct regional* region;
|
||||
/**
|
||||
* Hints are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qtype. Then on dname in nsec-like order, so that
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
* a lookup on class, name will return an exact match or the closest
|
||||
* match which gives the ancestor needed.
|
||||
* contents of type iter_hints_stub. The class IN root is in here.
|
||||
|
|
@ -105,6 +105,18 @@ int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg);
|
|||
*/
|
||||
struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass);
|
||||
|
||||
/**
|
||||
* Find next root hints (to cycle through all root hints).
|
||||
* @param hints: hint storage
|
||||
* @param qclass: class for which root hints are sought.
|
||||
* 0 means give the first available root hints class.
|
||||
* x means, give class x or a higher class if any.
|
||||
* returns the found class in this variable.
|
||||
* @return true if a root hint class is found.
|
||||
* false if not root hint class is found (qclass may have been changed).
|
||||
*/
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass);
|
||||
|
||||
/**
|
||||
* Given a qname/qclass combination, and the delegation point from the cache
|
||||
* for this qname/qclass, determine if this combination indicates that a
|
||||
|
|
|
|||
|
|
@ -734,3 +734,22 @@ iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp,
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
|
||||
uint16_t* c)
|
||||
{
|
||||
uint16_t c1 = *c, c2 = *c;
|
||||
int r1 = hints_next_root(hints, &c1);
|
||||
int r2 = forwards_next_root(fwd, &c2);
|
||||
if(!r1 && !r2) /* got none, end of list */
|
||||
return 0;
|
||||
else if(!r1) /* got one, return that */
|
||||
*c = c2;
|
||||
else if(!r2)
|
||||
*c = c1;
|
||||
else if(c1 < c2) /* got both take smallest */
|
||||
*c = c1;
|
||||
else *c = c2;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
#define ITERATOR_ITER_UTILS_H
|
||||
#include "iterator/iter_resptype.h"
|
||||
struct iter_env;
|
||||
struct iter_hints;
|
||||
struct iter_forwards;
|
||||
struct config_file;
|
||||
struct module_env;
|
||||
struct delegpt_addr;
|
||||
|
|
@ -232,4 +234,14 @@ void iter_store_inzone_glue(struct module_env* env, struct query_info* qinfo,
|
|||
int iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp,
|
||||
struct regional* region, struct query_info* qinfo);
|
||||
|
||||
/**
|
||||
* Lookup next root-hint or root-forward entry.
|
||||
* @param hints: the hints.
|
||||
* @param fwd: the forwards.
|
||||
* @param c: the class to start searching at. 0 means find first one.
|
||||
* @return false if no classes found, true if found and returned in c.
|
||||
*/
|
||||
int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
|
||||
uint16_t* c);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
|
|
|||
|
|
@ -853,6 +853,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
/* If the request is qclass=ANY, setup to generate each class */
|
||||
if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
|
||||
iq->qchase.qclass = 0;
|
||||
return next_state(iq, COLLECT_CLASS_STATE);
|
||||
}
|
||||
|
||||
/* Resolver Algorithm Step 1 -- Look for the answer in local data. */
|
||||
|
||||
/* This either results in a query restart (CNAME cache response), a
|
||||
|
|
@ -1903,6 +1909,150 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process response for qclass=ANY queries for a particular class.
|
||||
* Append to result or error-exit.
|
||||
*
|
||||
* @param qstate: query state.
|
||||
* @param id: module id.
|
||||
* @param forq: super query state.
|
||||
*/
|
||||
static void
|
||||
processClassResponse(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* forq)
|
||||
{
|
||||
struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
|
||||
struct dns_msg* from = qstate->return_msg;
|
||||
log_query_info(VERB_ALGO, "processClassResponse", &qstate->qinfo);
|
||||
log_query_info(VERB_ALGO, "processClassResponse super", &forq->qinfo);
|
||||
if(qstate->return_rcode != LDNS_RCODE_NOERROR) {
|
||||
/* cause servfail for qclass ANY query */
|
||||
foriq->response = NULL;
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
/* append result */
|
||||
if(!foriq->response) {
|
||||
/* allocate the response: copy RCODE, sec_state */
|
||||
foriq->response = dns_copy_msg(from, forq->region);
|
||||
if(!foriq->response) {
|
||||
log_err("malloc failed for qclass ANY response");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
foriq->response->qinfo.qclass = forq->qinfo.qclass;
|
||||
/* qclass ANY does not receive the AA flag on replies */
|
||||
foriq->response->rep->authoritative = 0;
|
||||
} else {
|
||||
struct dns_msg* to = foriq->response;
|
||||
/* add _from_ this response _to_ existing collection */
|
||||
/* if there are records, copy RCODE */
|
||||
/* lower sec_state if this message is lower */
|
||||
if(from->rep->rrset_count != 0) {
|
||||
size_t n = from->rep->rrset_count+to->rep->rrset_count;
|
||||
struct ub_packed_rrset_key** dest;
|
||||
/* copy appropriate rcode */
|
||||
to->rep->flags = from->rep->flags;
|
||||
/* copy rrsets */
|
||||
dest = regional_alloc(forq->region, sizeof(dest[0])*n);
|
||||
if(!dest) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
/* copy AN */
|
||||
memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
dest += to->rep->an_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
dest += from->rep->an_numrrsets;
|
||||
/* copy NS */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
|
||||
to->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ns_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
|
||||
from->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
dest += from->rep->ns_numrrsets;
|
||||
/* copy AR */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
|
||||
to->rep->ns_numrrsets,
|
||||
to->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ar_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
|
||||
from->rep->ns_numrrsets,
|
||||
from->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
/* update counts */
|
||||
to->rep->an_numrrsets += from->rep->an_numrrsets;
|
||||
to->rep->ns_numrrsets += from->rep->ns_numrrsets;
|
||||
to->rep->ar_numrrsets += from->rep->ar_numrrsets;
|
||||
to->rep->rrset_count = n;
|
||||
}
|
||||
if(from->rep->security < to->rep->security) /* lowest sec */
|
||||
to->rep->security = from->rep->security;
|
||||
if(from->rep->qdcount != 0) /* insert qd if appropriate */
|
||||
to->rep->qdcount = from->rep->qdcount;
|
||||
if(from->rep->ttl < to->rep->ttl) /* use smallest TTL */
|
||||
to->rep->ttl = from->rep->ttl;
|
||||
}
|
||||
/* are we done? */
|
||||
foriq->num_current_queries --;
|
||||
if(foriq->num_current_queries == 0)
|
||||
foriq->state = FINISHED_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect class ANY responses and make them into one response. This
|
||||
* state is started and it creates queries for all classes (that have
|
||||
* root hints). The answers are then collected.
|
||||
*
|
||||
* @param qstate: query state.
|
||||
* @param id: module id.
|
||||
* @return true if the event needs more immediate processing, false if not.
|
||||
*/
|
||||
static int
|
||||
processCollectClass(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
|
||||
struct module_qstate* subq;
|
||||
/* If qchase.qclass == 0 then send out queries for all classes.
|
||||
* Otherwise, do nothing (wait for all answers to arrive and the
|
||||
* processClassResponse to put them together, and that moves us
|
||||
* towards the Finished state when done. */
|
||||
if(iq->qchase.qclass == 0) {
|
||||
uint16_t c = 0;
|
||||
iq->qchase.qclass = LDNS_RR_CLASS_ANY;
|
||||
while(iter_get_next_root(ie->hints, qstate->env->fwds, &c)) {
|
||||
/* generate query for this class */
|
||||
log_nametypeclass(VERB_ALGO, "spawn collect query",
|
||||
qstate->qinfo.qname, qstate->qinfo.qtype, c);
|
||||
if(!generate_sub_request(qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, qstate->qinfo.qtype,
|
||||
c, qstate, id, iq, INIT_REQUEST_STATE,
|
||||
FINISHED_STATE, &subq,
|
||||
(int)!(qstate->query_flags&BIT_CD))) {
|
||||
return error_response(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
/* ignore subq, no special init required */
|
||||
iq->num_current_queries ++;
|
||||
if(c == 0xffff)
|
||||
break;
|
||||
else c++;
|
||||
}
|
||||
/* if no roots are configured at all, return */
|
||||
if(iq->num_current_queries == 0) {
|
||||
verbose(VERB_ALGO, "No hints or fwds, giving up "
|
||||
"on qclass ANY");
|
||||
return error_response(qstate, id, LDNS_RCODE_REFUSED);
|
||||
}
|
||||
/* return false, wait for queries to return */
|
||||
}
|
||||
/* if woke up here because of an answer, wait for more answers */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles the final state for first-tier responses (i.e., responses to
|
||||
* externally generated queries).
|
||||
|
|
@ -1979,7 +2129,9 @@ void
|
|||
iter_inform_super(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* super)
|
||||
{
|
||||
if(qstate->return_rcode != LDNS_RCODE_NOERROR)
|
||||
if(super->qinfo.qclass == LDNS_RR_CLASS_ANY)
|
||||
processClassResponse(qstate, id, super);
|
||||
else if(qstate->return_rcode != LDNS_RCODE_NOERROR)
|
||||
error_supers(qstate, id, super);
|
||||
else if(qstate->is_priming)
|
||||
prime_supers(qstate, id, super);
|
||||
|
|
@ -2025,6 +2177,9 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
case PRIME_RESP_STATE:
|
||||
cont = processPrimeResponse(qstate, id);
|
||||
break;
|
||||
case COLLECT_CLASS_STATE:
|
||||
cont = processCollectClass(qstate, id);
|
||||
break;
|
||||
case FINISHED_STATE:
|
||||
cont = processFinished(qstate, iq, id);
|
||||
break;
|
||||
|
|
@ -2252,6 +2407,8 @@ iter_state_to_string(enum iter_state state)
|
|||
return "QUERY TARGETS STATE";
|
||||
case PRIME_RESP_STATE :
|
||||
return "PRIME RESPONSE STATE";
|
||||
case COLLECT_CLASS_STATE :
|
||||
return "COLLECT CLASS STATE";
|
||||
case QUERY_RESP_STATE :
|
||||
return "QUERY RESPONSE STATE";
|
||||
case FINISHED_STATE :
|
||||
|
|
@ -2269,6 +2426,7 @@ iter_state_is_responsestate(enum iter_state s)
|
|||
case INIT_REQUEST_2_STATE :
|
||||
case INIT_REQUEST_3_STATE :
|
||||
case QUERYTARGETS_STATE :
|
||||
case COLLECT_CLASS_STATE :
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ enum iter_state {
|
|||
/** Responses to priming queries finish at this state. */
|
||||
PRIME_RESP_STATE,
|
||||
|
||||
/** Collecting query class information, for qclass=ANY, when
|
||||
* it spawns off queries for every class, it returns here. */
|
||||
COLLECT_CLASS_STATE,
|
||||
|
||||
/** Responses that are to be returned upstream end at this state.
|
||||
* As well as responses to target queries. */
|
||||
FINISHED_STATE
|
||||
|
|
|
|||
150
testdata/iter_class_any.rpl
vendored
Normal file
150
testdata/iter_class_any.rpl
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
; config options
|
||||
; The island of trust is at example.com
|
||||
server:
|
||||
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
|
||||
val-override-date: "20070916134226"
|
||||
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 lookup of class any response
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR 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
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. 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 NOERROR
|
||||
SECTION QUESTION
|
||||
com. IN NS
|
||||
SECTION ANSWER
|
||||
com. 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 NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
|
||||
example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN A 10.20.30.40
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD DO
|
||||
SECTION QUESTION
|
||||
www.example.com. ANY A
|
||||
ENTRY_END
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AD NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. ANY A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN A 10.20.30.40
|
||||
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
|
|
@ -230,3 +230,53 @@ struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
name_tree_next_root(rbtree_t* tree, uint16_t* dclass)
|
||||
{
|
||||
struct name_tree_node key;
|
||||
rbnode_t* n;
|
||||
struct name_tree_node* p;
|
||||
if(*dclass == 0) {
|
||||
/* first root item is first item in tree */
|
||||
n = rbtree_first(tree);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0;
|
||||
p = (struct name_tree_node*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* root not first item? search for higher items */
|
||||
*dclass = p->dclass + 1;
|
||||
return name_tree_next_root(tree, dclass);
|
||||
}
|
||||
/* find class n in tree, we may get a direct hit, or if we don't
|
||||
* this is the last item of the previous class so rbtree_next() takes
|
||||
* us to the next root (if any) */
|
||||
key.node.key = &key;
|
||||
key.name = (uint8_t*)"\000";
|
||||
key.len = 1;
|
||||
key.labs = 0;
|
||||
key.dclass = *dclass;
|
||||
n = NULL;
|
||||
if(rbtree_find_less_equal(tree, &key, &n)) {
|
||||
/* exact */
|
||||
return 1;
|
||||
} else {
|
||||
/* smaller element */
|
||||
if(!n || n == RBTREE_NULL)
|
||||
return 0; /* nothing found */
|
||||
n = rbtree_next(n);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0; /* no higher */
|
||||
p = (struct name_tree_node*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* not a root node, return next higher item */
|
||||
*dclass = p->dclass+1;
|
||||
return name_tree_next_root(tree, dclass);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,14 @@ struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
|
|||
struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
|
||||
size_t len, int labs, uint16_t dclass);
|
||||
|
||||
/**
|
||||
* Find next root item in name tree.
|
||||
* @param tree: the nametree.
|
||||
* @param dclass: the class to look for next (or higher).
|
||||
* @return false if no classes found, true means class put into c.
|
||||
*/
|
||||
int name_tree_next_root(rbtree_t* tree, uint16_t* dclass);
|
||||
|
||||
/**
|
||||
* Init addr tree to be empty.
|
||||
* @param tree: to init.
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ needs_validation(struct module_qstate* qstate, int ret_rc,
|
|||
verbose(VERB_ALGO, "cannot validate RRSIG, no sigs on sigs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2142,6 +2143,16 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
|||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
}
|
||||
/* qclass ANY should have validation result from spawned
|
||||
* queries. If we get here, it is bogus or an internal error */
|
||||
if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
|
||||
verbose(VERB_ALGO, "cannot validate classANY: bogus");
|
||||
if(qstate->return_msg)
|
||||
qstate->return_msg->rep->security =
|
||||
sec_status_bogus;
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
}
|
||||
/* create state to start validation */
|
||||
qstate->ext_state[id] = module_error; /* override this */
|
||||
if(!vq) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue