From: Wouter Wijngaards Date: Tue, 15 Dec 2009 09:10:04 +0000 (+0000) Subject: Answer qclass=ANY. X-Git-Tag: release-1.4.1~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ab9bd76768ab7546c8d814f007856f3bb7d36dd3;p=thirdparty%2Funbound.git Answer qclass=ANY. git-svn-id: file:///svn/unbound/trunk@1938 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 315502d8d..77b463bd3 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index a22662a8e..0d19c0c0a 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -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) { diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h index de58f5a5a..ea7bd22a1 100644 --- a/iterator/iter_fwd.h +++ b/iterator/iter_fwd.h @@ -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. diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index 15d759333..1ca46a12b 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -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) { diff --git a/iterator/iter_hints.h b/iterator/iter_hints.h index 343db0af7..8a3974489 100644 --- a/iterator/iter_hints.h +++ b/iterator/iter_hints.h @@ -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 diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index d364ae2a8..dec23ae9f 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -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; +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 4cc323380..e174d341a 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -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 */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 576038ef0..b2db0367a 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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; diff --git a/iterator/iterator.h b/iterator/iterator.h index b985860e2..736af51da 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -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 diff --git a/testdata/iter_class_any.rpl b/testdata/iter_class_any.rpl new file mode 100644 index 000000000..1256dfb5e --- /dev/null +++ b/testdata/iter_class_any.rpl @@ -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 diff --git a/util/storage/dnstree.c b/util/storage/dnstree.c index 1dd45dc36..003e8af3e 100644 --- a/util/storage/dnstree.c +++ b/util/storage/dnstree.c @@ -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); + } +} diff --git a/util/storage/dnstree.h b/util/storage/dnstree.h index 8255cf627..3ecbd128f 100644 --- a/util/storage/dnstree.h +++ b/util/storage/dnstree.h @@ -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. diff --git a/validator/validator.c b/validator/validator.c index 0e0582a5d..07a42b284 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -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) {