Answer qclass=ANY.

git-svn-id: file:///svn/unbound/trunk@1938 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-12-15 09:10:04 +00:00
parent 72926a9f8c
commit ab9bd76768
13 changed files with 494 additions and 3 deletions

View file

@ -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.

View file

@ -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)
{

View file

@ -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.

View file

@ -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)
{

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;

View file

@ -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
View 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

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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) {