diff --git a/doc/Changelog b/doc/Changelog index dd6c1f38c..64fbcad26 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,11 @@ 26 August 2011: Wouter - Fix num-threads 0 does not segfault, reported by Simon Deziel. + - Fix validation failures due to EDNS backoff retries, the retry + for fetch of data has want_dnssec because the iter_indicate_dnssec + function returns true when validation failure retry happens, and + then the serviced query code does not fallback to noEDNS, even if + the cache says it has this. This helps for DLV deployment when + the DNSSEC status is not known for sure before the lookup concludes. 24 August 2011: Wouter - Applied patch from Karel Slany that fixes a memory leak in the diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index dc1b3fe96..2bb216f1b 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -534,7 +534,7 @@ iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp, - struct dns_msg* msg, uint16_t dclass) + struct dns_msg* msg, uint16_t dclass, struct module_qstate* qstate) { struct trust_anchor* a; /* information not available, !env->anchors can be common */ @@ -568,6 +568,15 @@ iter_indicates_dnssec(struct module_env* env, struct delegpt* dp, regional_free_all(env->scratch); } } + /* on retries, we have to expect DNSSEC. + * just a blacklist of the cache is done for parentside lookups too, + * but blacklist of IPs is done for validation failures. */ + if(qstate && qstate->blacklist) { + struct sock_list* p; + for(p=qstate->blacklist; p; p=p->next) + if(p->len != 0) + return 1; + } return 0; } diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index deddac666..c7beeacc6 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -172,10 +172,12 @@ int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, * @param dp: delegation point. * @param msg: delegation message, with DS if a secure referral. * @param dclass: class of query. + * @param qstate: module query state for the query in question, for validation + * retry state. * @return 1 if dnssec is expected, 0 if not. */ int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp, - struct dns_msg* msg, uint16_t dclass); + struct dns_msg* msg, uint16_t dclass, struct module_qstate* qstate); /** * See if a message contains DNSSEC. diff --git a/iterator/iterator.c b/iterator/iterator.c index 3924057ce..e4bfa8d5d 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -574,8 +574,8 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, } /* there should not be any target queries. */ subiq->num_target_queries = 0; - subiq->dnssec_expected = iter_indicates_dnssec( - qstate->env, subiq->dp, NULL, subq->qinfo.qclass); + subiq->dnssec_expected = iter_indicates_dnssec(qstate->env, + subiq->dp, NULL, subq->qinfo.qclass, subq); } /* this module stops, our submodule starts, and does the query. */ @@ -669,8 +669,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, * missing targets. */ subiq->num_target_queries = 0; subiq->wait_priming_stub = 1; - subiq->dnssec_expected = iter_indicates_dnssec( - qstate->env, subiq->dp, NULL, subq->qinfo.qclass); + subiq->dnssec_expected = iter_indicates_dnssec(qstate->env, + subiq->dp, NULL, subq->qinfo.qclass, subq); } /* this module stops, our submodule starts, and does the query. */ @@ -1191,7 +1191,7 @@ processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq, /* if the cache reply dp equals a validation anchor or msg has DS, * then DNSSEC RRSIGs are expected in the reply */ iq->dnssec_expected = iter_indicates_dnssec(qstate->env, iq->dp, - iq->deleg_msg, iq->qchase.qclass); + iq->deleg_msg, iq->qchase.qclass, qstate); /* If the RD flag wasn't set, then we just finish with the * cached referral as the response. */ @@ -1254,7 +1254,7 @@ generate_parentside_target_query(struct module_qstate* qstate, subiq->dp = delegpt_copy(iq->dp, subq->region); subiq->dnssec_expected = iter_indicates_dnssec( qstate->env, subiq->dp, NULL, - subq->qinfo.qclass); + subq->qinfo.qclass, subq); subiq->refetch_glue = 1; } else { subiq->dp = dns_cache_find_delegation(qstate->env, @@ -1264,7 +1264,7 @@ generate_parentside_target_query(struct module_qstate* qstate, if(subiq->dp) { subiq->dnssec_expected = iter_indicates_dnssec( qstate->env, subiq->dp, NULL, - subq->qinfo.qclass); + subq->qinfo.qclass, subq); subiq->refetch_glue = 1; } } @@ -1897,7 +1897,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* see if the next dp is a trust anchor, or a DS was sent * along, indicating dnssec is expected for next zone */ iq->dnssec_expected = iter_indicates_dnssec(qstate->env, - iq->dp, iq->response, iq->qchase.qclass); + iq->dp, iq->response, iq->qchase.qclass, qstate); /* if dnssec, validating then also fetch the key for the DS */ if(iq->dnssec_expected && qstate->env->cfg->prefetch_key && !(qstate->query_flags&BIT_CD)) diff --git a/services/outside_network.c b/services/outside_network.c index 5397e8afb..59482c6ba 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1318,7 +1318,7 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff) /* even 700 msec may be too small */ rtt = 1000; sq->status = serviced_query_PROBE_EDNS; - } else if(vs != -1) { + } else if(vs != -1 || sq->want_dnssec) { sq->status = serviced_query_UDP_EDNS; } else { sq->status = serviced_query_UDP; @@ -1536,7 +1536,7 @@ serviced_tcp_send(struct serviced_query* sq, ldns_buffer* buff) if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, *sq->outnet->now_secs, &vs, &edns_lame_known, &rtt)) return 0; - if(vs != -1) + if(vs != -1 || sq->want_dnssec) sq->status = serviced_query_TCP_EDNS; else sq->status = serviced_query_TCP; serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS);