From bc7f906590cdd898b843e2efd170eb6ab466f03c Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Tue, 24 Jun 2014 08:24:28 +0000 Subject: [PATCH] - Fix caps-for-id fallback, and added fallback attempt when servers drop 0x20 perturbed queries. git-svn-id: file:///svn/unbound/trunk@3146 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 8 ++++---- doc/Changelog | 4 ++++ iterator/iterator.c | 27 +++++++++++++++++++++++---- iterator/iterator.h | 3 ++- libunbound/libworker.c | 9 +++++---- libunbound/worker.h | 12 ++++++++---- services/outside_network.c | 16 +++++++++------- services/outside_network.h | 12 ++++++++---- smallapp/worker_cb.c | 4 ++-- testcode/fake_event.c | 7 ++++--- util/fptr_wlist.c | 2 +- util/fptr_wlist.h | 2 +- util/module.h | 4 +++- 13 files changed, 74 insertions(+), 36 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index dbdf28c54..4611114ea 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1293,8 +1293,8 @@ worker_delete(struct worker* worker) 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( @@ -1303,7 +1303,7 @@ 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, 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); @@ -1350,7 +1350,7 @@ struct outbound_entry* libworker_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), 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), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) { diff --git a/doc/Changelog b/doc/Changelog index af1f79a24..20ca8e7a0 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +24 June 2014: Wouter + - Fix caps-for-id fallback, and added fallback attempt when servers + drop 0x20 perturbed queries. + 17 June 2014: Wouter - iana portlist updated. diff --git a/iterator/iterator.c b/iterator/iterator.c index f240f5034..df5f645cc 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1854,8 +1854,8 @@ 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, - 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); @@ -2765,6 +2765,21 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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) @@ -2813,7 +2828,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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; @@ -2825,7 +2840,11 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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"); diff --git a/iterator/iterator.h b/iterator/iterator.h index fc3d7285a..0b91760d4 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -230,7 +230,8 @@ struct iter_qstate { 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 */ diff --git a/libunbound/libworker.c b/libunbound/libworker.c index fa5418063..c5807f062 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -821,8 +821,9 @@ void libworker_alloc_cleanup(void* arg) 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( @@ -831,7 +832,7 @@ 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, 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); @@ -953,7 +954,7 @@ 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), 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), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) { diff --git a/libunbound/worker.h b/libunbound/worker.h index d8354c654..824012a01 100644 --- a/libunbound/worker.h +++ b/libunbound/worker.h @@ -58,6 +58,7 @@ struct tube; * @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. @@ -68,8 +69,9 @@ struct tube; */ 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, @@ -111,6 +113,7 @@ void worker_sighandler(int sig, void* arg); * @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: wireformat dname of the zone. @@ -121,8 +124,9 @@ void worker_sighandler(int sig, void* arg); */ 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 diff --git a/services/outside_network.c b/services/outside_network.c index 4baa1080d..a2083db24 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1206,7 +1206,7 @@ lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec, /** 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) { @@ -1233,6 +1233,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, 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); @@ -1350,7 +1351,7 @@ static void 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 */ @@ -1828,10 +1829,11 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, 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; @@ -1844,7 +1846,7 @@ outnet_serviced_query(struct outside_network* outnet, 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) { diff --git a/services/outside_network.h b/services/outside_network.h index a56a205c3..b9124b57f 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -309,6 +309,8 @@ struct serviced_query { 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 */ @@ -466,6 +468,7 @@ void pending_delete(struct outside_network* outnet, struct pending* p); * 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. @@ -482,10 +485,11 @@ 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, 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. diff --git a/smallapp/worker_cb.c b/smallapp/worker_cb.c index 035d9087a..8193bec1b 100644 --- a/smallapp/worker_cb.c +++ b/smallapp/worker_cb.c @@ -103,7 +103,7 @@ 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), 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), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) { @@ -135,7 +135,7 @@ struct outbound_entry* libworker_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), 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), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) { diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 47e4b78da..83ac805d5 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1037,9 +1037,10 @@ pending_tcp_query(struct outside_network* outnet, sldns_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, 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; diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index 7aa773634..35fcd8c7e 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -258,7 +258,7 @@ fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr) 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)) diff --git a/util/fptr_wlist.h b/util/fptr_wlist.h index b2925d675..62692ba8b 100644 --- a/util/fptr_wlist.h +++ b/util/fptr_wlist.h @@ -211,7 +211,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr); */ 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)); diff --git a/util/module.h b/util/module.h index dace1cf6b..f95ff6dc8 100644 --- a/util/module.h +++ b/util/module.h @@ -212,6 +212,8 @@ struct module_env { * 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 module_env { */ 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); -- 2.47.2