try other servers when receiving FORMERR

previously, when an iterative query returned FORMERR, resolution
would be stopped under the assumption that other servers for
the same domain would likely have the same capabilities. this
assumption is not correct; some domains have been reported for
which some but not all servers will return FORMERR to a given
query; retrying allows recursion to succeed.
This commit is contained in:
Evan Hunt 2022-07-01 14:23:33 -07:00
parent 8aac0262c0
commit f6abb80746
7 changed files with 25 additions and 21 deletions

View file

@ -13,7 +13,7 @@
rm -f ns*/named.conf
rm -f */named.memstats
rm -f */named.run
rm -f */named.run */named.run.prev
rm -f dig.out.*
rm -f ns*/named.lock
rm -f ans*/query.log*

View file

@ -272,7 +272,7 @@ $RNDCCMD 10.53.0.7 flush
n=$((n+1))
echo_i "information that minimization was unsuccessful for .ugly is logged ($n)"
ret=0
grep "success resolving 'icky.icky.icky.ptang.zoop.boing.ugly/A' after disabling qname minimization due to 'FORMERR'" ns7/named.run > /dev/null || ret=1
wait_for_log 5 "success resolving 'icky.icky.icky.ptang.zoop.boing.ugly/A' after disabling qname minimization" ns7/named.run > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))

View file

@ -122,6 +122,8 @@ for (;;) {
# Delegation to broken TLD.
$packet->push("authority", new Net::DNS::RR("broken 300 NS ns.broken"));
$packet->push("additional", new Net::DNS::RR("ns.broken 300 A 10.53.0.4"));
} elsif ($qname =~ /\.partial-formerr/) {
$packet->header->rcode("FORMERR");
} else {
# Data for the "bogus referrals" test
$packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com"));

View file

@ -125,6 +125,9 @@ for (;;) {
$packet->push("answer",
new Net::DNS::RR($qname .
" 300 A 10.53.0.3"));
} elsif ($qname =~ /\.partial-formerr/) {
$packet->push("answer",
new Net::DNS::RR($qname . " 1 A 10.53.0.3"));
} else {
$packet->push("answer", new Net::DNS::RR("www.example.com 300 A 1.2.3.4"));
}

View file

@ -32,3 +32,6 @@ sourcens. NS ns.sourcens.
ns.sourcens. A 10.53.0.4
targetns. NS ns.targetns.
ns.targetns. A 10.53.0.6
partial-formerr. NS ns.partial-formerr.
ns.partial-formerr. A 10.53.0.2
ns.partial-formerr. A 10.53.0.3

View file

@ -862,6 +862,14 @@ grep "status: SERVFAIL" dig.ns5.out.${n} > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n+1))
echo_i "checking SERVFAIL is not returned if only some authoritative servers return FORMERR ($n)"
ret=0
dig_with_opts @10.53.0.5 ns.partial-formerr. a > dig.ns5.out.${n} || ret=1
grep "status: SERVFAIL" dig.ns5.out.${n} > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n+1))
echo_i "check logged command line ($n)"
ret=0

View file

@ -9890,25 +9890,13 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res, dns_resstatscounter_edns0fail);
} else if (rcode == dns_rcode_formerr) {
if (ISFORWARDER(query->addrinfo)) {
/*
* This forwarder doesn't understand us,
* but other forwarders might. Keep trying.
*/
rctx->broken_server = DNS_R_REMOTEFORMERR;
rctx->next_server = true;
} else {
/*
* The server doesn't understand us. Since
* all servers for a zone need similar
* capabilities, we assume that we will get
* FORMERR from all servers, and thus we
* cannot make any more progress with this
* fetch.
*/
log_formerr(fctx, "server sent FORMERR");
result = DNS_R_FORMERR;
}
/*
* The server (or forwarder) doesn't understand us,
* but others might.
*/
rctx->next_server = true;
rctx->broken_server = DNS_R_REMOTEFORMERR;
log_formerr(fctx, "server sent FORMERR");
} else if (rcode == dns_rcode_badvers) {
unsigned int version;
#if DNS_EDNS_VERSION > 0