Index: unbound-1.4.22/daemon/worker.c =================================================================== --- unbound-1.4.22.orig/daemon/worker.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/daemon/worker.c 2014-06-26 07:35:47.000000000 +0200 @@ -1291,8 +1291,8 @@ struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* q) + int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* q) { struct worker* worker = q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -1301,7 +1301,7 @@ return NULL; e->qstate = q; e->qsent = outnet_serviced_query(worker->back, qname, - qnamelen, qtype, qclass, flags, dnssec, want_dnssec, + qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, addrlen, zone, zonelen, worker_handle_service_reply, e, worker->back->udp_buff); @@ -1347,7 +1347,7 @@ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); Index: unbound-1.4.22/daemon/worker.h =================================================================== --- unbound-1.4.22.orig/daemon/worker.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/daemon/worker.h 2014-06-26 07:35:09.000000000 +0200 @@ -173,6 +173,7 @@ * @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 nocaps: do not use capsforid. * @param addr: where to. * @param addrlen: length of addr. * @param zone: wireformat dname of the zone. @@ -183,8 +184,9 @@ */ struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* q); + int want_dnssec, int nocaps, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + struct module_qstate* q); /** * process control messages from the main thread. Frees the control Index: unbound-1.4.22/iterator/iterator.c =================================================================== --- unbound-1.4.22.orig/iterator/iterator.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/iterator/iterator.c 2014-06-26 07:35:09.000000000 +0200 @@ -1846,8 +1846,8 @@ 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, - iq->dnssec_expected, &target->addr, target->addrlen, - iq->dp->name, iq->dp->namelen, qstate); + iq->dnssec_expected, iq->caps_fallback, &target->addr, + target->addrlen, iq->dp->name, iq->dp->namelen, qstate); if(!outq) { log_addr(VERB_DETAIL, "error sending query to auth server", &target->addr, target->addrlen); @@ -2757,6 +2757,21 @@ iq->response = NULL; iq->state = QUERY_RESP_STATE; if(event == module_event_noreply || event == module_event_error) { + if(event == module_event_noreply && iq->sent_count >= 3 && + qstate->env->cfg->use_caps_bits_for_id && + !iq->caps_fallback) { + /* start fallback */ + iq->caps_fallback = 1; + iq->caps_server = 0; + iq->caps_reply = NULL; + iq->state = QUERYTARGETS_STATE; + iq->num_current_queries--; + /* need fresh attempts for the 0x20 fallback, if + * that was the cause for the failure */ + iter_dec_attempts(iq->dp, 3); + verbose(VERB_DETAIL, "Capsforid: timeouts, starting fallback"); + goto handle_it; + } goto handle_it; } if( (event != module_event_reply && event != module_event_capsfail) @@ -2805,7 +2820,7 @@ log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo, iq->response->rep); - if(event == module_event_capsfail) { + if(event == module_event_capsfail || iq->caps_fallback) { if(!iq->caps_fallback) { /* start fallback */ iq->caps_fallback = 1; @@ -2817,7 +2832,11 @@ goto handle_it; } else { /* check if reply is the same, otherwise, fail */ - if(!reply_equal(iq->response->rep, iq->caps_reply, + if(!iq->caps_reply) { + iq->caps_reply = iq->response->rep; + iq->caps_server = -1; /*become zero at ++, + so that we start the full set of trials */ + } else if(!reply_equal(iq->response->rep, iq->caps_reply, qstate->env->scratch)) { verbose(VERB_DETAIL, "Capsforid fallback: " "getting different replies, failed"); Index: unbound-1.4.22/iterator/iterator.h =================================================================== --- unbound-1.4.22.orig/iterator/iterator.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/iterator/iterator.h 2014-06-26 07:35:09.000000000 +0200 @@ -234,7 +234,8 @@ int caps_fallback; /** state for capsfail: current server number to try */ size_t caps_server; - /** state for capsfail: stored query for comparisons */ + /** state for capsfail: stored query for comparisons. Can be NULL if + * no response had been seen prior to starting the fallback. */ struct reply_info* caps_reply; /** Current delegation message - returned for non-RD queries */ Index: unbound-1.4.22/libunbound/libworker.c =================================================================== --- unbound-1.4.22.orig/libunbound/libworker.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/libunbound/libworker.c 2014-06-26 07:35:39.000000000 +0200 @@ -819,8 +819,9 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* q) + int want_dnssec, int nocaps, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + struct module_qstate* q) { struct libworker* w = (struct libworker*)q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -829,7 +830,7 @@ return NULL; e->qstate = q; e->qsent = outnet_serviced_query(w->back, qname, - qnamelen, qtype, qclass, flags, dnssec, want_dnssec, + qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, addrlen, zone, zonelen, libworker_handle_service_reply, e, w->back->udp_buff); @@ -951,7 +952,7 @@ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); Index: unbound-1.4.22/libunbound/libworker.h =================================================================== --- unbound-1.4.22.orig/libunbound/libworker.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/libunbound/libworker.h 2014-06-26 07:35:09.000000000 +0200 @@ -145,6 +145,7 @@ * @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 nocaps: ignore capsforid(if in config), do not perturb qname. * @param addr: where to. * @param addrlen: length of addr. * @param zone: delegation point name. @@ -155,8 +156,9 @@ */ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* q); + int want_dnssec, int nocaps, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + struct module_qstate* q); /** process incoming replies from the network */ int libworker_handle_reply(struct comm_point* c, void* arg, int error, Index: unbound-1.4.22/services/outside_network.c =================================================================== --- unbound-1.4.22.orig/services/outside_network.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/services/outside_network.c 2014-06-26 07:35:09.000000000 +0200 @@ -1205,7 +1205,7 @@ /** Create new serviced entry */ static struct serviced_query* serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, - int want_dnssec, int tcp_upstream, int ssl_upstream, + int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int qtype) { @@ -1232,6 +1232,7 @@ sq->qtype = qtype; sq->dnssec = dnssec; sq->want_dnssec = want_dnssec; + sq->nocaps = nocaps; sq->tcp_upstream = tcp_upstream; sq->ssl_upstream = ssl_upstream; memcpy(&sq->addr, addr, addrlen); @@ -1349,7 +1350,7 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns) { /* if we are using 0x20 bits for ID randomness, perturb them */ - if(sq->outnet->use_caps_for_id) { + if(sq->outnet->use_caps_for_id && !sq->nocaps) { serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen); } /* generate query */ @@ -1827,10 +1828,11 @@ 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, int want_dnssec, int tcp_upstream, - int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, comm_point_callback_t* callback, - void* callback_arg, sldns_buffer* buff) + uint16_t flags, int dnssec, int want_dnssec, int nocaps, + int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + comm_point_callback_t* callback, void* callback_arg, + sldns_buffer* buff) { struct serviced_query* sq; struct service_callback* cb; @@ -1843,7 +1845,7 @@ return NULL; if(!sq) { /* make new serviced query entry */ - sq = serviced_create(outnet, buff, dnssec, want_dnssec, + sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, tcp_upstream, ssl_upstream, addr, addrlen, zone, zonelen, (int)qtype); if(!sq) { Index: unbound-1.4.22/services/outside_network.h =================================================================== --- unbound-1.4.22.orig/services/outside_network.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/services/outside_network.h 2014-06-26 07:35:09.000000000 +0200 @@ -307,6 +307,8 @@ int dnssec; /** We want signatures, or else the answer is likely useless */ int want_dnssec; + /** ignore capsforid */ + int nocaps; /** tcp upstream used, use tcp, or ssl_upstream for SSL */ int tcp_upstream, ssl_upstream; /** where to send it */ @@ -464,6 +466,7 @@ * 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 nocaps: ignore use_caps_for_id and use unperturbed qname. * @param tcp_upstream: use TCP for upstream queries. * @param ssl_upstream: use SSL for upstream queries. * @param callback: callback function. @@ -480,10 +483,11 @@ */ 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, int want_dnssec, int tcp_upstream, - int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, comm_point_callback_t* callback, - void* callback_arg, struct sldns_buffer* buff); + uint16_t flags, int dnssec, int want_dnssec, int nocaps, + int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + comm_point_callback_t* callback, void* callback_arg, + struct sldns_buffer* buff); /** * Remove service query callback. Index: unbound-1.4.22/smallapp/worker_cb.c =================================================================== --- unbound-1.4.22.orig/smallapp/worker_cb.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/smallapp/worker_cb.c 2014-06-26 07:35:29.000000000 +0200 @@ -104,7 +104,7 @@ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); @@ -135,7 +135,7 @@ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); Index: unbound-1.4.22/testcode/fake_event.c =================================================================== --- unbound-1.4.22.orig/testcode/fake_event.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/testcode/fake_event.c 2014-06-26 07:35:09.000000000 +0200 @@ -1037,9 +1037,10 @@ 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, int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, comm_point_callback_t* callback, void* callback_arg, + int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream), + int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, + comm_point_callback_t* callback, void* callback_arg, sldns_buffer* ATTR_UNUSED(buff)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; Index: unbound-1.4.22/util/fptr_wlist.c =================================================================== --- unbound-1.4.22.orig/util/fptr_wlist.c 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/util/fptr_wlist.c 2014-06-26 07:35:09.000000000 +0200 @@ -259,7 +259,7 @@ 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, int want_dnssec, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* q)) Index: unbound-1.4.22/util/fptr_wlist.h =================================================================== --- unbound-1.4.22.orig/util/fptr_wlist.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/util/fptr_wlist.h 2014-06-26 07:35:09.000000000 +0200 @@ -211,7 +211,7 @@ */ 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, int want_dnssec, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* q)); Index: unbound-1.4.22/util/module.h =================================================================== --- unbound-1.4.22.orig/util/module.h 2014-06-26 07:33:09.000000000 +0200 +++ unbound-1.4.22/util/module.h 2014-06-26 07:35:56.000000000 +0200 @@ -212,6 +212,8 @@ * 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 nocaps: do not use caps_for_id, use the qname as given. + * (ignored if caps_for_id is disabled). * @param addr: where to. * @param addrlen: length of addr. * @param zone: delegation point name. @@ -224,7 +226,7 @@ */ struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, struct sockaddr_storage* addr, + int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* q);