]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix EDNS probe for .de DNSSEC testbed failure, where the infra
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 6 Apr 2010 08:35:37 +0000 (08:35 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 6 Apr 2010 08:35:37 +0000 (08:35 +0000)
  cache timeout coincided with a server update, the current EDNS
  backoff is less sensitive, and does not cache the backoff unless
  the backoff actually works and the domain is not expecting DNSSEC.

git-svn-id: file:///svn/unbound/trunk@2063 be551aaa-1e26-0410-a405-d3ace91eadb9

12 files changed:
daemon/worker.c
daemon/worker.h
iterator/iterator.c
libunbound/libworker.c
libunbound/libworker.h
services/outside_network.c
services/outside_network.h
smallapp/worker_cb.c
testcode/fake_event.c
util/fptr_wlist.c
util/fptr_wlist.h
util/module.h

index 76e51353349dc64bec555038fbab908783725f42..db4712b2b1479f785e32ba98ea4c1a004ffc3ad0 100644 (file)
@@ -1248,7 +1248,7 @@ outbound_entry_compare(void* a, void* b)
 
 struct outbound_entry*
 worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
-       uint16_t qclass, uint16_t flags, int dnssec,
+       uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
        struct sockaddr_storage* addr, socklen_t addrlen,
        struct module_qstate* q)
 {
@@ -1259,9 +1259,9 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(worker->back, qname,
-               qnamelen, qtype, qclass, flags, dnssec, addr, addrlen, 
-               worker_handle_service_reply, e, worker->back->udp_buff,
-               &outbound_entry_compare);
+               qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
+               addr, addrlen, worker_handle_service_reply, e, 
+               worker->back->udp_buff, &outbound_entry_compare);
        if(!e->qsent) {
                return NULL;
        }
index 2116d54d87e907d5bc1c88670845338f00b4bcca..b1fa95ebab4a3432833bbaf1ddb811e2ca802688 100644 (file)
@@ -189,6 +189,7 @@ int worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
  * @param qclass: query class. (host order)
  * @param flags: host order flags word, with opcode and CD bit.
  * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param want_dnssec: signatures needed.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @param q: wich query state to reactivate upon return.
@@ -197,7 +198,7 @@ int worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
  */
 struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, 
        uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 
-       struct sockaddr_storage* addr, socklen_t addrlen,
+       int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
        struct module_qstate* q);
 
 /** 
index d8b5588a7f26e466354ee4de8ff1e9830c893d34..e8345c8045e1d9876f1ca1b3303c5865cc5d2eaf 100644 (file)
@@ -1521,7 +1521,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                iq->qchase.qname, iq->qchase.qname_len, 
                iq->qchase.qtype, iq->qchase.qclass, 
                iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD, 
-               &target->addr, target->addrlen, qstate);
+               iq->dnssec_expected, &target->addr, target->addrlen, qstate);
        if(!outq) {
                log_addr(VERB_DETAIL, "error sending query to auth server", 
                        &target->addr, target->addrlen);
index 0c28b76151b7b9220938b1c3695682e41fb6b3d1..ae15c3d2eec6ec3454670ea2047cb95557ed14dc 100644 (file)
@@ -696,7 +696,7 @@ outbound_entry_compare(void* a, void* b)
 
 struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
         uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
-        struct sockaddr_storage* addr, socklen_t addrlen,
+       int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
         struct module_qstate* q)
 {
        struct libworker* w = (struct libworker*)q->env->worker;
@@ -706,9 +706,9 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(w->back, qname,
-               qnamelen, qtype, qclass, flags, dnssec, addr, addrlen,
-               libworker_handle_service_reply, e, w->back->udp_buff,
-               &outbound_entry_compare);
+               qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
+               addr, addrlen, libworker_handle_service_reply, e, 
+               w->back->udp_buff, &outbound_entry_compare);
        if(!e->qsent) {
                return NULL;
        }
index 74ae894438dc2716cd2a14a9017088051c62f5d6..192094d8d72f071163dabc857b84551e332a68f8 100644 (file)
@@ -129,6 +129,7 @@ int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
  * @param qclass: query class. (host order)
  * @param flags: host order flags word, with opcode and CD bit.
  * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param want_dnssec: signatures needed.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @param q: wich query state to reactivate upon return.
@@ -137,7 +138,7 @@ int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
  */
 struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
         uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
-        struct sockaddr_storage* addr, socklen_t addrlen,
+       int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
         struct module_qstate* q);
 
 /** process incoming replies from the network */
index e1c5265d7329a1073322a685fb4fc0fbb8ed9ec4..3725c636ba577e116a5a8819a19cabff1dd04092 100644 (file)
@@ -1077,7 +1077,7 @@ lookup_serviced(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
 /** Create new serviced entry */
 static struct serviced_query*
 serviced_create(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
-        struct sockaddr_storage* addr, socklen_t addrlen)
+       int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen)
 {
        struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
        rbnode_t* ins;
@@ -1091,6 +1091,7 @@ serviced_create(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
        }
        sq->qbuflen = ldns_buffer_limit(buff);
        sq->dnssec = dnssec;
+       sq->want_dnssec = want_dnssec;
        memcpy(&sq->addr, addr, addrlen);
        sq->addrlen = addrlen;
        sq->outnet = outnet;
@@ -1132,7 +1133,8 @@ serviced_delete(struct serviced_query* sq)
                /* clear up the pending query */
                if(sq->status == serviced_query_UDP_EDNS ||
                        sq->status == serviced_query_UDP ||
-                       sq->status == serviced_query_PROBE_EDNS) {
+                       sq->status == serviced_query_PROBE_EDNS ||
+                       sq->status == serviced_query_UDP_EDNS_fallback) {
                        struct pending* p = (struct pending*)sq->pending;
                        if(p->pc)
                                portcomm_loweruse(sq->outnet, p->pc);
@@ -1409,12 +1411,25 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
                (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) == 
                LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(ldns_buffer_begin(
                c->buffer)) == LDNS_RCODE_NOTIMPL) ) {
-               if(!infra_edns_update(sq->outnet->infra, &sq->addr, 
+               /* attempt to fallback to nonEDNS */
+               sq->status = serviced_query_TCP_EDNS_fallback;
+               serviced_tcp_initiate(sq->outnet, sq, c->buffer);
+               return 0;
+       } else if(error==NETEVENT_NOERROR && 
+               sq->status == serviced_query_TCP_EDNS_fallback &&
+                       (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) == 
+                       LDNS_RCODE_NOERROR || LDNS_RCODE_WIRE(
+                       ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NXDOMAIN 
+                       || LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) 
+                       == LDNS_RCODE_YXDOMAIN)) {
+               /* the fallback produced a result that looks promising, note
+                * that this server should be approached without EDNS */
+               /* only store noEDNS in cache if domain is noDNSSEC */
+               if(!sq->want_dnssec)
+                 if(!infra_edns_update(sq->outnet->infra, &sq->addr, 
                        sq->addrlen, -1, *sq->outnet->now_secs))
                        log_err("Out of memory caching no edns for host");
                sq->status = serviced_query_TCP;
-               serviced_tcp_initiate(sq->outnet, sq, c->buffer);
-               return 0;
        }
        /* insert address into reply info */
        if(!rep) {
@@ -1504,43 +1519,33 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
                        serviced_callbacks(sq, NETEVENT_TIMEOUT, c, rep);
                        return 0;
                }
+       } else if(error != NETEVENT_NOERROR) {
+               /* udp returns error (due to no ID or interface available) */
+               serviced_callbacks(sq, error, c, rep);
+               return 0;
        }
-       if(error == NETEVENT_NOERROR && sq->status == serviced_query_UDP_EDNS 
+       if(sq->status == serviced_query_UDP_EDNS 
                && (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) 
                        == LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(
                        ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) {
-               /* note no EDNS, fallback without EDNS */
-               if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
-                       -1, (uint32_t)now.tv_sec)) {
-                       log_err("Out of memory caching no edns for host");
-               }
-               sq->status = serviced_query_UDP;
+               /* try to get an answer by falling back without EDNS */
+               sq->status = serviced_query_UDP_EDNS_fallback;
                sq->retry = 0;
                if(!serviced_udp_send(sq, c->buffer)) {
                        serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
                }
                return 0;
-       }
-       if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) ||
-               (error != NETEVENT_NOERROR && fallback_tcp)  ) {
-               /* fallback to TCP */
-               /* this discards partial UDP contents */
-               if(sq->status == serviced_query_UDP_EDNS)
-                       sq->status = serviced_query_TCP_EDNS;
-               else    sq->status = serviced_query_TCP;
-               serviced_tcp_initiate(outnet, sq, c->buffer);
-               return 0;
-       }
-       /* yay! an answer */
-       if(sq->status == serviced_query_PROBE_EDNS) {
+       } else if(sq->status == serviced_query_PROBE_EDNS) {
                /* probe without EDNS succeeds, so we conclude that this
                 * host likely has EDNS packets dropped */
                log_addr(VERB_DETAIL, "timeouts, concluded that connection to "
                        "host drops EDNS packets", &sq->addr, sq->addrlen);
-               if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
+               /* only store noEDNS in cache if domain is noDNSSEC */
+               if(!sq->want_dnssec)
+                 if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
                        -1, (uint32_t)now.tv_sec)) {
                        log_err("Out of memory caching no edns for host");
-               }
+                 }
                sq->status = serviced_query_UDP;
        } else if(sq->status == serviced_query_UDP_EDNS && 
                !sq->edns_lame_known) {
@@ -1550,6 +1555,21 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
                        log_err("Out of memory caching edns works");
                }
                sq->edns_lame_known = 1;
+       } else if(sq->status == serviced_query_UDP_EDNS_fallback &&
+               !sq->edns_lame_known && (LDNS_RCODE_WIRE(
+               ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOERROR || 
+               LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) == 
+               LDNS_RCODE_NXDOMAIN || LDNS_RCODE_WIRE(ldns_buffer_begin(
+               c->buffer)) == LDNS_RCODE_YXDOMAIN)) {
+               /* the fallback produced a result that looks promising, note
+                * that this server should be approached without EDNS */
+               /* only store noEDNS in cache if domain is noDNSSEC */
+               if(!sq->want_dnssec)
+                 if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
+                       -1, (uint32_t)now.tv_sec)) {
+                       log_err("Out of memory caching no edns for host");
+                 }
+               sq->status = serviced_query_UDP;
        }
        if(now.tv_sec > sq->last_sent_time.tv_sec ||
                (now.tv_sec == sq->last_sent_time.tv_sec &&
@@ -1563,6 +1583,20 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
                        roundtime, sq->last_rtt, (uint32_t)now.tv_sec))
                        log_err("out of memory noting rtt.");
        }
+       /* perform TC flag check and TCP fallback after updating our
+        * cache entries for EDNS status and RTT times */
+       if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) || fallback_tcp) {
+               /* fallback to TCP */
+               /* this discards partial UDP contents */
+               if(sq->status == serviced_query_UDP_EDNS ||
+                       sq->status == serviced_query_UDP_EDNS_fallback)
+                       /* if we have unfinished EDNS_fallback, start again */
+                       sq->status = serviced_query_TCP_EDNS;
+               else    sq->status = serviced_query_TCP;
+               serviced_tcp_initiate(outnet, sq, c->buffer);
+               return 0;
+       }
+       /* yay! an answer */
        serviced_callbacks(sq, error, c, rep);
        return 0;
 }
@@ -1583,10 +1617,10 @@ callback_list_find(struct serviced_query* sq, void* cb_arg,
 struct serviced_query* 
 outnet_serviced_query(struct outside_network* outnet,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-       uint16_t flags, int dnssec, struct sockaddr_storage* addr,
-       socklen_t addrlen, comm_point_callback_t* callback,
-       void* callback_arg, ldns_buffer* buff
-       int (*arg_compare)(void*,void*))
+       uint16_t flags, int dnssec, int want_dnssec,
+       struct sockaddr_storage* addr, socklen_t addrlen, 
+       comm_point_callback_t* callback, void* callback_arg
+       ldns_buffer* buff, int (*arg_compare)(void*,void*))
 {
        struct serviced_query* sq;
        struct service_callback* cb;
@@ -1602,7 +1636,8 @@ outnet_serviced_query(struct outside_network* outnet,
                return NULL;
        if(!sq) {
                /* make new serviced query entry */
-               sq = serviced_create(outnet, buff, dnssec, addr, addrlen);
+               sq = serviced_create(outnet, buff, dnssec, want_dnssec,
+                       addr, addrlen);
                if(!sq) {
                        free(cb);
                        return NULL;
@@ -1754,7 +1789,8 @@ serviced_get_mem(struct serviced_query* sq)
                s += sizeof(*sb);
        if(sq->status == serviced_query_UDP_EDNS ||
                sq->status == serviced_query_UDP ||
-               sq->status == serviced_query_PROBE_EDNS) {
+               sq->status == serviced_query_PROBE_EDNS ||
+               sq->status == serviced_query_UDP_EDNS_fallback) {
                s += sizeof(struct pending);
                s += comm_timer_get_mem(NULL);
        } else {
index 342682524d219b56614bc7d6cb43883884f1df9b..f918ff1825a72e2c1bfb7704a887c9fc88070f97 100644 (file)
@@ -291,6 +291,8 @@ struct serviced_query {
        size_t qbuflen;
        /** If an EDNS section is included, the DO/CD bit will be turned on. */
        int dnssec;
+       /** We want signatures, or else the answer is likely useless */
+       int want_dnssec;
        /** where to send it */
        struct sockaddr_storage addr;
        /** length of addr field in use. */
@@ -308,7 +310,11 @@ struct serviced_query {
                /** TCP without EDNS sent */
                serviced_query_TCP,
                /** probe to test EDNS lameness (EDNS is dropped) */
-               serviced_query_PROBE_EDNS
+               serviced_query_PROBE_EDNS,
+               /** probe to test noEDNS0 (EDNS gives FORMERRorNOTIMP) */
+               serviced_query_UDP_EDNS_fallback,
+               /** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */
+               serviced_query_TCP_EDNS_fallback
        }       
                /** variable with current status */ 
                status;
@@ -427,6 +433,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
  * @param dnssec: if set, DO bit is set in EDNS queries.
  *     If the value includes BIT_CD, CD bit is set when in EDNS queries.
  *     If the value includes BIT_DO, DO bit is set when in EDNS queries.
+ * @param want_dnssec: signatures are needed, without EDNS the answer is
+ *     likely to be useless.
  * @param callback: callback function.
  * @param callback_arg: user argument to callback function.
  * @param addr: to which server to send the query.
@@ -439,10 +447,10 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
  */
 struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-       uint16_t flags, int dnssec, struct sockaddr_storage* addr, 
-       socklen_t addrlen, comm_point_callback_t* callback
-       void* callback_arg, ldns_buffer* buff
-       int (*arg_compare)(void*,void*));
+       uint16_t flags, int dnssec, int want_dnssec,
+       struct sockaddr_storage* addr, socklen_t addrlen
+       comm_point_callback_t* callback, void* callback_arg
+       ldns_buffer* buff, int (*arg_compare)(void*,void*));
 
 /**
  * Remove service query callback.
index 78ee0196349ccad3bec5ced2aa5337715b5e5099..b72c5613071e53817e6efcc505cfe4643b4a2882 100644 (file)
@@ -112,7 +112,8 @@ int worker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
 struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), 
        size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 
        uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
-       int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr), 
+       int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 
+       struct sockaddr_storage* ATTR_UNUSED(addr), 
        socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
 {
        log_assert(0);
index 29135c4100e0ca89f573da93973790bf0699f9b2..4fffccb26bdee3740e1e8f0b8fd508c4b3f6475b 100644 (file)
@@ -988,10 +988,10 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
 
 struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
         uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-       uint16_t flags, int dnssec, struct sockaddr_storage* addr,
-       socklen_t addrlen, comm_point_callback_t* callback,
-       void* callback_arg, ldns_buffer* ATTR_UNUSED(buff),
-       int (*arg_compare)(void*,void*))
+       uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
+       struct sockaddr_storage* addr, socklen_t addrlen, 
+       comm_point_callback_t* callback, void* callback_arg, 
+       ldns_buffer* ATTR_UNUSED(buff), int (*arg_compare)(void*,void*))
 {
        struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
        struct fake_pending* pend = (struct fake_pending*)calloc(1,
index 5d96382d81185b1c951b232c60482d958dcdca5d..d57d96c7a21d1f56c5695b4222320033a6392fb8 100644 (file)
@@ -258,8 +258,9 @@ fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
 int 
 fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
         uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
-        uint16_t flags, int dnssec, struct sockaddr_storage* addr,
-        socklen_t addrlen, struct module_qstate* q))
+        uint16_t flags, int dnssec, int want_dnssec, 
+       struct sockaddr_storage* addr, socklen_t addrlen, 
+       struct module_qstate* q))
 {
        if(fptr == &worker_send_query) return 1;
        else if(fptr == &libworker_send_query) return 1;
index 331626df4cc354cdcae82fdda9e8147182f879f4..7301cbf3ae7895d2cbc297d386d3d03417b72c29 100644 (file)
@@ -201,8 +201,9 @@ int fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
  */
 int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, 
-       uint16_t flags, int dnssec, struct sockaddr_storage* addr, 
-       socklen_t addrlen, struct module_qstate* q));
+       uint16_t flags, int dnssec, int want_dnssec,
+       struct sockaddr_storage* addr, socklen_t addrlen, 
+       struct module_qstate* q));
 
 /**
  * Check function pointer whitelist for module_env detach_subs callback values.
index f2ff7b1be99ccda616198df51dc396871d67aeea..89dfffd85e99ae80881508a02a74e9495806b2f8 100644 (file)
@@ -114,6 +114,8 @@ struct module_env {
         * @param dnssec: if set, EDNS record will have bits set.
         *      If EDNS_DO bit is set, DO bit is set in EDNS records.
         *      If BIT_CD is set, CD bit is set in queries with EDNS records.
+        * @param want_dnssec: if set, the validator wants DNSSEC.  Without
+        *      EDNS, the answer is likely to be useless for this domain.
         * @param addr: where to.
         * @param addrlen: length of addr.
         * @param q: wich query state to reactivate upon return.
@@ -124,8 +126,8 @@ struct module_env {
         */
        struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen, 
                uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 
-               struct sockaddr_storage* addr, socklen_t addrlen
-               struct module_qstate* q);
+               int want_dnssec, struct sockaddr_storage* addr
+               socklen_t addrlen, struct module_qstate* q);
 
        /**
         * Detach-subqueries.