]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
0x20 fallback code.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 6 Oct 2008 14:46:22 +0000 (14:46 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 6 Oct 2008 14:46:22 +0000 (14:46 +0000)
git-svn-id: file:///svn/unbound/trunk@1285 be551aaa-1e26-0410-a405-d3ace91eadb9

15 files changed:
daemon/worker.c
doc/Changelog
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
iterator/iterator.h
libunbound/libworker.c
services/mesh.c
services/mesh.h
services/outside_network.c
testdata/fwd_capsid.tpkg [new file with mode: 0644]
testdata/fwd_capsid_fallback.tpkg [new file with mode: 0644]
util/module.c
util/module.h
util/netevent.h

index 3c06c552bc2ca9f75b0a1785d604f2fb0cef8df3..19a1271dde0f5f8cf5e492185f4c71a2bed18900 100644 (file)
@@ -211,7 +211,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
        e.qsent = NULL;
 
        if(error != 0) {
-               mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
+               mesh_report_reply(worker->env.mesh, &e, reply_info, error);
                worker_mem_report(worker, NULL);
                return 0;
        }
@@ -222,11 +222,12 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
                || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
                /* error becomes timeout for the module as if this reply
                 * never arrived. */
-               mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
+               mesh_report_reply(worker->env.mesh, &e, reply_info, 
+                       NETEVENT_TIMEOUT);
                worker_mem_report(worker, NULL);
                return 0;
        }
-       mesh_report_reply(worker->env.mesh, &e, 1, reply_info);
+       mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR);
        worker_mem_report(worker, NULL);
        return 0;
 }
@@ -241,7 +242,7 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
 
        verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
        if(error != 0) {
-               mesh_report_reply(worker->env.mesh, e, 0, reply_info);
+               mesh_report_reply(worker->env.mesh, e, reply_info, error);
                worker_mem_report(worker, sq);
                return 0;
        }
@@ -253,11 +254,12 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
                /* error becomes timeout for the module as if this reply
                 * never arrived. */
                verbose(VERB_ALGO, "worker: bad reply handled as timeout");
-               mesh_report_reply(worker->env.mesh, e, 0, reply_info);
+               mesh_report_reply(worker->env.mesh, e, reply_info, 
+                       NETEVENT_TIMEOUT);
                worker_mem_report(worker, sq);
                return 0;
        }
-       mesh_report_reply(worker->env.mesh, e, 1, reply_info);
+       mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
        worker_mem_report(worker, sq);
        return 0;
 }
index 069adddfb91627e7d6613a784b0e2674a2b7f1fd..6606ad501e216337407e67d5d7bb37278f43a4fb 100644 (file)
@@ -1,5 +1,7 @@
 6 October 2008: Wouter
        - jostle-timeout option, so you can config for slow links.
+       - 0x20 fallback code.  Tries 3xnumber of nameserver addresses
+         queries that must all be the same.  Sent to random nameservers.
 
 2 October 2008: Wouter
        - fixup unlink of pidfile.
index d9ea574b1504df139b93aae521b80780920fb920..4c894219912d23f1665ad2a8110b9f7eb10bb63f 100644 (file)
@@ -484,3 +484,60 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
                return 1;
        return 0;
 }
+
+/**
+ * check equality of two rrsets 
+ * @param k1: rrset
+ * @param k2: rrset
+ * @return true if equal
+ */
+static int
+rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
+{
+       struct packed_rrset_data* d1 = (struct packed_rrset_data*)
+               k1->entry.data;
+       struct packed_rrset_data* d2 = (struct packed_rrset_data*)
+               k2->entry.data;
+       size_t i, t;
+       if(k1->rk.dname_len != k2->rk.dname_len ||
+               k1->rk.flags != k2->rk.flags ||
+               k1->rk.type != k2->rk.type ||
+               k1->rk.rrset_class != k2->rk.rrset_class ||
+               query_dname_compare(k1->rk.dname, k2->rk.dname) != 0)
+               return 0;
+       if(d1->ttl != d2->ttl ||
+               d1->count != d2->count ||
+               d1->rrsig_count != d2->rrsig_count ||
+               d1->trust != d2->trust ||
+               d1->security != d2->security)
+               return 0;
+       t = d1->count + d1->rrsig_count;
+       for(i=0; i<t; i++) {
+               if(d1->rr_len[i] != d2->rr_len[i] ||
+                       d1->rr_ttl[i] != d2->rr_ttl[i] ||
+                       memcmp(d1->rr_data[i], d2->rr_data[i], 
+                               d1->rr_len[i]) != 0)
+                       return 0;
+       }
+       return 1;
+}
+
+int 
+reply_equal(struct reply_info* p, struct reply_info* q)
+{
+       size_t i;
+       if(p->flags != q->flags ||
+               p->qdcount != q->qdcount ||
+               p->ttl != q->ttl ||
+               p->security != q->security ||
+               p->an_numrrsets != q->an_numrrsets ||
+               p->ns_numrrsets != q->ns_numrrsets ||
+               p->ar_numrrsets != q->ar_numrrsets ||
+               p->rrset_count != q->rrset_count)
+               return 0;
+       for(i=0; i<p->rrset_count; i++) {
+               if(!rrset_equal(p->rrsets[i], q->rrsets[i]))
+                       return 0;
+       }
+       return 1;
+}
index 7055fbaa66068218c47b7eb2313ba837c8c0f936..1d3872294232f13b1d9cc69b464d9a3a20895d1e 100644 (file)
@@ -180,4 +180,14 @@ int iter_msg_has_dnssec(struct dns_msg* msg);
 int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, 
        enum response_type type, uint16_t dclass);
 
+/**
+ * Check if two replies are equal
+ * For fallback procedures
+ * @param p: reply one. The reply has rrset data pointers in region.
+ *     Does not check rrset-IDs
+ * @param q: reply two
+ * @return if one and two are equal.
+ */
+int reply_equal(struct reply_info* p, struct reply_info* q);
+
 #endif /* ITERATOR_ITER_UTILS_H */
index 0decd27bea91a149e65e5b0ac473e482158e1199..4f2a25f5b499472a2761723f49336806b94caad6 100644 (file)
@@ -1153,11 +1153,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                tf_policy = ie->target_fetch_policy[iq->depth];
        }
 
+       /* if in 0x20 fallback get as many targets as possible */
+       if(iq->caps_fallback) {
+               int extra = 0;
+               size_t naddr, nres, navail;
+               if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
+                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+               }
+               iq->num_target_queries += extra;
+               if(iq->num_target_queries > 0) {
+                       /* wait to get all targets, we want to try em */
+                       verbose(VERB_ALGO, "wait for all targets for fallback");
+                       return 0;
+               }
+               /* did we do enough fallback queries already? */
+               delegpt_count_addr(iq->dp, &naddr, &nres, &navail);
+               /* the current caps_server is the number of fallbacks sent.
+                * the original query is one that matched too, so we have
+                * caps_server+1 number of matching queries now */
+               if(iq->caps_server+1 >= naddr*3) {
+                       /* we're done, process the response */
+                       verbose(VERB_ALGO, "0x20 fallback had %d responses "
+                               "match for %d wanted, done.", 
+                               (int)iq->caps_server+1, (int)naddr*3);
+                       iq->caps_fallback = 0;
+                       iq->state = QUERY_RESP_STATE;
+                       return 1;
+               }
+               verbose(VERB_ALGO, "0x20 fallback number %d", 
+                       (int)iq->caps_server);
+
        /* if there is a policy to fetch missing targets 
         * opportunistically, do it. we rely on the fact that once a 
         * query (or queries) for a missing name have been issued, 
         * they will not be show up again. */
-       if(tf_policy != 0) {
+       } else if(tf_policy != 0) {
                int extra = 0;
                verbose(VERB_ALGO, "attempt to get extra %d targets", 
                        tf_policy);
@@ -1760,7 +1790,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
        if(event == module_event_noreply || event == module_event_error) {
                goto handle_it;
        }
-       if(event != module_event_reply || !qstate->reply) {
+       if( (event != module_event_reply && event != module_event_capsfail)
+               || !qstate->reply) {
                log_err("Bad event combined with response");
                outbound_list_remove(&iq->outlist, outbound);
                (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@@ -1804,6 +1835,37 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
        if(verbosity >= VERB_ALGO)
                log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo, 
                        iq->response->rep);
+       
+       if(event == module_event_capsfail) {
+               if(!iq->caps_fallback) {
+                       /* start fallback */
+                       iq->caps_fallback = 1;
+                       iq->caps_server = 0;
+                       iq->caps_reply = iq->response->rep;
+                       iq->state = QUERYTARGETS_STATE;
+                       iq->num_current_queries--;
+                       verbose(VERB_DETAIL, "Capsforid: starting fallback");
+                       goto handle_it;
+               } else {
+                       /* check if reply is the same, otherwise, fail */
+                       if(!reply_equal(iq->response->rep, iq->caps_reply)) {
+                               verbose(VERB_DETAIL, "Capsforid fallback: "
+                                       "getting different replies, failed");
+                               outbound_list_remove(&iq->outlist, outbound);
+                               (void)error_response(qstate, id, 
+                                       LDNS_RCODE_SERVFAIL);
+                               return;
+                       }
+                       /* continue the fallback procedure at next server */
+                       iq->caps_server++;
+                       iq->state = QUERYTARGETS_STATE;
+                       iq->num_current_queries--;
+                       verbose(VERB_DETAIL, "Capsforid: reply is equal. "
+                               "go to next fallback");
+                       goto handle_it;
+               }
+       }
+       iq->caps_fallback = 0; /* if we were in fallback, 0x20 is OK now */
 
 handle_it:
        outbound_list_remove(&iq->outlist, outbound);
index 775e50d3c0d0b6ebc8731e8e226a0b4f75f2b696..f8b1b2ca068e5f1635b9620bdaed147154e86ba6 100644 (file)
@@ -218,6 +218,13 @@ struct iter_qstate {
         */
        struct delegpt* dp;
 
+       /** state for 0x20 fallback when capsfail happens, 0 not a fallback */
+       int caps_fallback;
+       /** state for capsfail: current server number to try */
+       size_t caps_server;
+       /** state for capsfail: stored query for comparisons */
+       struct reply_info* caps_reply;
+
        /** Current delegation message - returned for non-RD queries */
        struct dns_msg* deleg_msg;
 
index 846d90b8656bbd4ba66242b2fd9b245679bc9928..47e1b378f2e996d3fcf42a8824733a5755d21a37 100644 (file)
@@ -695,7 +695,7 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
        e.qsent = NULL;
 
        if(error != 0) {
-               mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+               mesh_report_reply(lw->env->mesh, &e, reply_info, error);
                return 0;
        }
        /* sanity check. */
@@ -705,10 +705,11 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
                || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
                /* error becomes timeout for the module as if this reply
                 * never arrived. */
-               mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+               mesh_report_reply(lw->env->mesh, &e, reply_info, 
+                       NETEVENT_TIMEOUT);
                return 0;
        }
-       mesh_report_reply(lw->env->mesh, &e, 1, reply_info);
+       mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
        return 0;
 }
 
@@ -720,7 +721,7 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
        struct libworker* lw = (struct libworker*)e->qstate->env->worker;
 
        if(error != 0) {
-               mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+               mesh_report_reply(lw->env->mesh, e, reply_info, error);
                return 0;
        }
        /* sanity check. */
@@ -730,10 +731,11 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
                || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
                /* error becomes timeout for the module as if this reply
                 * never arrived. */
-               mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+               mesh_report_reply(lw->env->mesh, e, reply_info, 
+                       NETEVENT_TIMEOUT);
                return 0;
        }
-       mesh_report_reply(lw->env->mesh,  e, 1, reply_info);
+       mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
        return 0;
 }
 
index 3b0f3b8d9cea65aa83a3c029e83ae2d469305702..b3ad7f2a2e783d5587755fab289b593cdc10c115 100644 (file)
@@ -363,11 +363,16 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
 }
 
 void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
-        int is_ok, struct comm_reply* reply)
+        struct comm_reply* reply, int what)
 {
+       enum module_ev event = module_event_reply;
        e->qstate->reply = reply;
-       mesh_run(mesh, e->qstate->mesh_info,
-               is_ok?module_event_reply:module_event_noreply, e);
+       if(what != NETEVENT_NOERROR) {
+               event = module_event_noreply;
+               if(what == NETEVENT_CAPSFAIL)
+                       event = module_event_capsfail;
+       }
+       mesh_run(mesh, e->qstate->mesh_info, event, e);
 }
 
 struct mesh_state* 
index 25900212737b420788cd0ddbee32196a0d237055..61c5bd11178db2f61d690a64187071ec5a73ddde 100644 (file)
@@ -289,11 +289,11 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
  *
  * @param mesh: the query mesh.
  * @param e: outbound entry, with query state to run and reply pointer.
- * @param is_ok: if true, reply is OK, otherwise a timeout happened.
  * @param reply: the comm point reply info.
+ * @param what: NETEVENT_* error code (if not 0, what is wrong, TIMEOUT).
  */
 void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
-       int is_ok, struct comm_reply* reply);
+       struct comm_reply* reply, int what);
 
 /* ------------------- Functions for module environment --------------- */
 
index 2e6a185ff7b82cb0fe0e7c0963dd164b84b78b7a..003dfb90231ff177bedf993330521cfaea14858f 100644 (file)
@@ -1284,22 +1284,23 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
                                == LDNS_RCODE_NOERROR || 
                         LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
                                == LDNS_RCODE_NXDOMAIN)) {
-                       verbose(VERB_OPS, "no qname in reply to check 0x20ID");
-                       log_addr(VERB_OPS, "from server", 
+                       verbose(VERB_DETAIL, "no qname in reply to check 0x20ID");
+                       log_addr(VERB_DETAIL, "from server", 
                                &sq->addr, sq->addrlen);
-                       log_buf(VERB_OPS, "for packet", c->buffer);
+                       log_buf(VERB_DETAIL, "for packet", c->buffer);
                        error = NETEVENT_CLOSED;
                        c = NULL;
                } else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
                        !serviced_check_qname(c->buffer, sq->qbuf, 
                        sq->qbuflen)) {
-                       verbose(VERB_OPS, "wrong 0x20-ID in reply qname, "
-                               "answer dropped");
-                       log_addr(VERB_OPS, "from server", 
+                       verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname");
+                       log_addr(VERB_DETAIL, "from server", 
                                &sq->addr, sq->addrlen);
-                       log_buf(VERB_OPS, "for packet", c->buffer);
-                       error = NETEVENT_CLOSED;
-                       c = NULL;
+                       log_buf(VERB_DETAIL, "for packet", c->buffer);
+                       error = NETEVENT_CAPSFAIL;
+                       /* and cleanup too */
+                       pkt_dname_tolower(c->buffer, 
+                               ldns_buffer_at(c->buffer, 12));
                } else {
                        verbose(VERB_ALGO, "good 0x20-ID in reply qname");
                        /* cleanup caps, prettier cache contents. */
diff --git a/testdata/fwd_capsid.tpkg b/testdata/fwd_capsid.tpkg
new file mode 100644 (file)
index 0000000..da16f43
Binary files /dev/null and b/testdata/fwd_capsid.tpkg differ
diff --git a/testdata/fwd_capsid_fallback.tpkg b/testdata/fwd_capsid_fallback.tpkg
new file mode 100644 (file)
index 0000000..a110759
Binary files /dev/null and b/testdata/fwd_capsid_fallback.tpkg differ
index 60c9489ecca5f5ef466a6001f6a5013e9b91df44..2079eecfec9a31215cbbe75c447273c06a5a973e 100644 (file)
@@ -62,6 +62,7 @@ strmodulevent(enum module_ev e)
        case module_event_pass: return "module_event_pass";
        case module_event_reply: return "module_event_reply";
        case module_event_noreply: return "module_event_noreply";
+       case module_event_capsfail: return "module_event_capsfail";
        case module_event_moddone: return "module_event_moddone";
        case module_event_error: return "module_event_error";
        }
index 43551ef2049efb094a5bcb0f25d0edb6b6ed638e..831212b1f70ba850b22a85ad7c16d07dbd051377 100644 (file)
@@ -239,6 +239,8 @@ enum module_ev {
        module_event_reply,
        /** no reply, timeout or other error */
        module_event_noreply,
+       /** reply is there, but capitalisation check failed */
+       module_event_capsfail,
        /** next module is done, and its reply is awaiting you */
        module_event_moddone,
        /** error */
index bc2b72d38bd06e67254558833d183773808ae50c..9cbe388867e0d86340e27ad2053b10d638843c8f 100644 (file)
@@ -80,6 +80,8 @@ typedef int comm_point_callback_t(struct comm_point*, void*, int,
 #define NETEVENT_CLOSED -1
 /** to pass timeout happened to callback function */
 #define NETEVENT_TIMEOUT -2 
+/** to pass fallback from capsforID to callback function; 0x20 failed */
+#define NETEVENT_CAPSFAIL -3
 
 /**
  * A communication point dispatcher. Thread specific.