diff --git a/doc/Changelog b/doc/Changelog index 100ffc612..a3b05b49a 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,10 @@ 4 March 2015: Wouter - Patch from Brad Smith that syncs compat/getentropy_linux with OpenBSD's version (2015-03-04). + - 0x20 fallback improved, better handling of servfail responses, + they do not count as missing comparisons (except if all are failed), + and better handling of inability to find nameservers, no more + nameservers can be found results in fallback acceptance. 3 March 2015: Wouter - tag 1.5.3rc1 diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 10ae12f75..8c90653c0 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -750,6 +750,12 @@ caps_strip_reply(struct reply_info* rep) } } +int caps_failed_rcode(struct reply_info* rep) +{ + return !(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || + FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN); +} + void iter_store_parentside_rrset(struct module_env* env, struct ub_packed_rrset_key* rrset) diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 9373487e0..3a4df3e45 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -231,6 +231,14 @@ int reply_equal(struct reply_info* p, struct reply_info* q, struct regional* reg */ void caps_strip_reply(struct reply_info* rep); +/** + * see if reply has a 'useful' rcode for capsforid comparison, so + * not SERVFAIL or REFUSED, and thus NOERROR or NXDOMAIN. + * @param rep: reply to check. + * @return true if the rcode is a bad type of message. + */ +int caps_failed_rcode(struct reply_info* rep); + /** * Store parent-side rrset in seperate rrset cache entries for later * last-resort * lookups in case the child-side versions of this information diff --git a/iterator/iterator.c b/iterator/iterator.c index 2037cc881..cd7e5b36b 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1866,6 +1866,23 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* Since a target query might have been made, we * need to check again. */ if(iq->num_target_queries == 0) { + /* if in capsforid fallback, instead of last + * resort, we agree with the current reply + * we have (if any) (our count of addrs bad)*/ + if(iq->caps_fallback && iq->caps_reply) { + /* we're done, process the response */ + verbose(VERB_ALGO, "0x20 fallback had %d responses, " + "but no more servers except " + "last resort, done.", + (int)iq->caps_server+1); + iq->caps_fallback = 0; + iter_dec_attempts(iq->dp, 3); /* space for fallback */ + iq->num_current_queries++; /* RespState decrements it*/ + iq->referral_count++; /* make sure we don't loop */ + iq->sent_count = 0; + iq->state = QUERY_RESP_STATE; + return 1; + } return processLastResort(qstate, iq, ie, id); } } @@ -2900,6 +2917,20 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->caps_reply = iq->response->rep; iq->caps_server = -1; /*become zero at ++, so that we start the full set of trials */ + } else if(caps_failed_rcode(iq->caps_reply) && + !caps_failed_rcode(iq->response->rep)) { + /* prefer to upgrade to non-SERVFAIL */ + iq->caps_reply = iq->response->rep; + } else if(!caps_failed_rcode(iq->caps_reply) && + caps_failed_rcode(iq->response->rep)) { + /* if we have non-SERVFAIL as answer then + * we can ignore SERVFAILs for the equality + * comparison */ + /* no instructions here, skip other else */ + } else if(caps_failed_rcode(iq->caps_reply) && + caps_failed_rcode(iq->response->rep)) { + /* failure is same as other failure in fallbk*/ + /* no instructions here, skip other else */ } else if(!reply_equal(iq->response->rep, iq->caps_reply, qstate->env->scratch)) { verbose(VERB_DETAIL, "Capsforid fallback: "