]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Answer qclass=ANY.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 Dec 2009 09:10:04 +0000 (09:10 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 Dec 2009 09:10:04 +0000 (09:10 +0000)
git-svn-id: file:///svn/unbound/trunk@1938 be551aaa-1e26-0410-a405-d3ace91eadb9

13 files changed:
doc/Changelog
iterator/iter_fwd.c
iterator/iter_fwd.h
iterator/iter_hints.c
iterator/iter_hints.h
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
iterator/iterator.h
testdata/iter_class_any.rpl [new file with mode: 0644]
util/storage/dnstree.c
util/storage/dnstree.h
validator/validator.c

index 315502d8d732f1219232eb1fbb3b0c9b2284141b..77b463bd35fb6b6c5f33ecadac42d46cd226c747 100644 (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.
 
index a22662a8eba03ab9878ccf339a90c53b72582a4f..0d19c0c0a64368a1849d9c29542b27dd3d596767 100644 (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)
 {
index de58f5a5a5de8878cbf01b429d17aa9b4dc2a3ae..ea7bd22a16d1d26905f5f32c5c6616b815f8ea86 100644 (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.
index 15d7593333a0585b4ba06dc3646bf38c96a076ee..1ca46a12bc1bd4734e41690da83362c6fbaf522a 100644 (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)
 {
index 343db0af7ff81558a0af5fdbd7c5db3bb944bf8c..8a3974489b46f48846bac23b1ad76729d675245e 100644 (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
index d364ae2a896e0a68d84efb9acef96590e898b687..dec23ae9f1c5295473eeaea18171e1003f8c41b4 100644 (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;
+}
index 4cc3233801d69cf060b472c3f8fa84ed7bad8e7f..e174d341a17b1200947662e4b494250fd89d11a2 100644 (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 */
index 576038ef05e8979c21dc1263cfd322c6881fa595..b2db0367a6481352e5d2050818de25f2914110c1 100644 (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;
index b985860e2fcf95088e001e75a0d82cde3fde04b5..736af51dadb0519bb3d2b13160fca8989bd520ae 100644 (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
diff --git a/testdata/iter_class_any.rpl b/testdata/iter_class_any.rpl
new file mode 100644 (file)
index 0000000..1256dfb
--- /dev/null
@@ -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
index 1dd45dc362c565b0482809d11b24114e923a6869..003e8af3ef315dd8ecf3e21a7dc12f5513bf930e 100644 (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);
+       }
+}
index 8255cf627a5aa052ab98037d183f589564cd4ae6..3ecbd128f8ce9265b7683ff5ad1a8a43f266f18b 100644 (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.
index 0e0582a5d49a8cf0a93a21ba05474635426b8e73..07a42b28400591bc573e04a1b1ec3c84abf20a8a 100644 (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) {