Commit 38f96de9 authored by Mark Andrews's avatar Mark Andrews

Merge branch '150-remove-workarounds-for-servers-that-are-not-edns-compliant' into 'master'

Resolve "Remove workarounds for servers that are not EDNS compliant."

Closes #150

See merge request !555
parents c0c80df2 5e371908
Pipeline #4550 passed with stages
in 8 minutes and 49 seconds
5029. [func] Workarounds for servers that misbehave when queried
with EDNS have been removed, because these broken
servers and the workarounds for their noncompliance
cause unnecessary delays, increase code complexity,
and prevent deployment of new DNS features. See
https://dnsflagday.net for further details. [GL #150]
5028. [bug] Spread the initial RRSIG expiration times over the
entire working sig-validity-interval when signing a
zone in named to even out re-signing and transfer
......
......@@ -122,14 +122,17 @@ static int maxudp = 0;
*/
static bool clienttest = false;
static bool dropedns = false;
static bool noedns = false;
static bool nosoa = false;
static bool ednsformerr = false;
static bool ednsnotimp = false;
static bool ednsrefused = false;
static bool fixedlocal = false;
static bool noaa = false;
static unsigned int delay = 0;
static bool noedns = false;
static bool nonearest = false;
static bool nosoa = false;
static bool notcp = false;
static bool fixedlocal = false;
static bool sigvalinsecs = false;
static unsigned int delay = 0;
/*
* -4 and -6
......@@ -488,6 +491,12 @@ parse_T_opt(char *option) {
dropedns = true;
} else if (!strncmp(option, "dscp=", 5)) {
isc_dscp_check_value = atoi(option + 5);
} else if (!strcmp(option, "ednsformerr")) {
ednsformerr = true;
} else if (!strcmp(option, "ednsnotimp")) {
ednsnotimp = true;
} else if (!strcmp(option, "ednsrefused")) {
ednsrefused = true;
} else if (!strcmp(option, "fixedlocal")) {
fixedlocal = true;
} else if (!strcmp(option, "keepstderr")) {
......@@ -547,7 +556,7 @@ parse_T_opt(char *option) {
} else if (!strncmp(option, "tat=", 4)) {
named_g_tat_interval = atoi(option + 4);
} else {
fprintf(stderr, "unknown -T flag '%s\n", option);
fprintf(stderr, "unknown -T flag '%s'\n", option);
}
}
......@@ -1159,24 +1168,30 @@ setup(void) {
*/
if (clienttest)
ns_server_setoption(sctx, NS_SERVER_CLIENTTEST, true);
if (disable4)
ns_server_setoption(sctx, NS_SERVER_DISABLE4, true);
if (disable6)
ns_server_setoption(sctx, NS_SERVER_DISABLE6, true);
if (dropedns)
ns_server_setoption(sctx, NS_SERVER_DROPEDNS, true);
if (noedns)
ns_server_setoption(sctx, NS_SERVER_NOEDNS, true);
if (nosoa)
ns_server_setoption(sctx, NS_SERVER_NOSOA, true);
if (ednsformerr) /* STD13 server */
ns_server_setoption(sctx, NS_SERVER_EDNSFORMERR, true);
if (ednsnotimp)
ns_server_setoption(sctx, NS_SERVER_EDNSNOTIMP, true);
if (ednsrefused)
ns_server_setoption(sctx, NS_SERVER_EDNSREFUSED, true);
if (fixedlocal)
ns_server_setoption(sctx, NS_SERVER_FIXEDLOCAL, true);
if (noaa)
ns_server_setoption(sctx, NS_SERVER_NOAA, true);
if (noedns)
ns_server_setoption(sctx, NS_SERVER_NOEDNS, true);
if (nonearest)
ns_server_setoption(sctx, NS_SERVER_NONEAREST, true);
if (nosoa)
ns_server_setoption(sctx, NS_SERVER_NOSOA, true);
if (notcp)
ns_server_setoption(sctx, NS_SERVER_NOTCP, true);
if (fixedlocal)
ns_server_setoption(sctx, NS_SERVER_FIXEDLOCAL, true);
if (disable4)
ns_server_setoption(sctx, NS_SERVER_DISABLE4, true);
if (disable6)
ns_server_setoption(sctx, NS_SERVER_DISABLE6, true);
if (sigvalinsecs)
ns_server_setoption(sctx, NS_SERVER_SIGVALINSECS, true);
......
......@@ -12,10 +12,10 @@
#
# Set up interface aliases for bind9 system tests.
#
# IPv4: 10.53.0.{1..8} RFC 1918
# IPv4: 10.53.0.{1..10} RFC 1918
# 10.53.1.{0..2}
# 10.53.2.{0..2}
# IPv6: fd92:7065:b8e:ffff::{1..8} ULA
# IPv6: fd92:7065:b8e:ffff::{1..10} ULA
# fd92:7065:b8e:99ff::{1..2}
# fd92:7065:b8e:ff::{1..2}
#
......@@ -65,7 +65,7 @@ case "$1" in
2) ipv6="00" ;;
*) ipv6="" ;;
esac
for ns in 1 2 3 4 5 6 7 8
for ns in 1 2 3 4 5 6 7 8 9 10
do
[ $i -gt 0 -a $ns -gt 2 ] && break
int=`expr $i \* 10 + $ns`
......@@ -171,7 +171,7 @@ case "$1" in
2) ipv6="00" ;;
*) ipv6="" ;;
esac
for ns in 8 7 6 5 4 3 2 1
for ns in 10 9 8 7 6 5 4 3 2 1
do
[ $i -gt 0 -a $ns -gt 2 ] && continue
int=`expr $i \* 10 + $ns - 1`
......
......@@ -8,9 +8,9 @@
# information regarding copyright ownership.
rm -f dig.out.*
rm -f ns?/named.conf
rm -f ns?/named.memstats
rm -f ns?/named.run
rm -f ns*/named.conf
rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/named.lock
# build.sh
......
......@@ -23,3 +23,9 @@ edns512. NS ns.edns512.
ns.edns512. A 10.53.0.6
edns512-notcp. NS ns.edns512-notcp.
ns.edns512-notcp. A 10.53.0.7
ednsformerr. NS ns.ednsformerr.
ns.ednsformerr. A 10.53.0.8
ednsnotimp. NS ns.ednsnotimp.
ns.ednsnotimp. A 10.53.0.9
ednsrefused. NS ns.ednsrefused.
ns.ednsrefused. A 10.53.0.10
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 60 SOA ns marka.isc.org. 1 0 0 0 0
@ 60 NS ns
ns 60 A 10.53.0.8
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.10;
notify-source 10.53.0.10;
transfer-source 10.53.0.10;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.10; };
listen-on-v6 { none; };
recursion no;
dnssec-validation no;
};
zone "ednsrefused" {
type master;
file "ednsrefused.db";
};
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 60 SOA ns marka.isc.org. 1 0 0 0 0
@ 60 NS ns
ns 60 A 10.53.0.8
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.8;
notify-source 10.53.0.8;
transfer-source 10.53.0.8;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.8; };
listen-on-v6 { none; };
recursion no;
dnssec-validation no;
};
zone "ednsformerr" {
type master;
file "ednsformerr.db";
};
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 60 SOA ns marka.isc.org. 1 0 0 0 0
@ 60 NS ns
ns 60 A 10.53.0.8
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.9;
notify-source 10.53.0.9;
transfer-source 10.53.0.9;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.9; };
listen-on-v6 { none; };
recursion no;
dnssec-validation no;
};
zone "ednsnotimp" {
type master;
file "ednsnotimp.db";
};
......@@ -15,10 +15,12 @@ SYSTEMTESTTOP=..
$SHELL clean.sh
copy_setports ns1/named1.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf
copy_setports ns6/named.conf.in ns6/named.conf
copy_setports ns7/named.conf.in ns7/named.conf
copy_setports ns8/named.conf.in ns8/named.conf
copy_setports ns9/named.conf.in ns9/named.conf
copy_setports ns10/named.conf.in ns10/named.conf
......@@ -17,6 +17,60 @@ DIGOPTS="-p ${PORT}"
status=0
n=0
n=`expr $n + 1`
echo_i "checking formerr edns server setup ($n)"
ret=0
$DIG $DIGOPTS +edns @10.53.0.8 ednsformerr soa > dig.out.1.test$n || ret=1
grep "status: FORMERR" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +noedns @10.53.0.8 ednsformerr soa > dig.out.2.test$n || ret=1
grep "status: NOERROR" dig.out.2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to formerr edns server succeeds ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 ednsformerr soa > dig.out.test$n || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking notimp edns server setup ($n)"
ret=0
$DIG $DIGOPTS +edns @10.53.0.9 ednsnotimp soa > dig.out.1.test$n || ret=1
grep "status: NOTIMP" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +noedns @10.53.0.9 ednsnotimp soa > dig.out.2.test$n || ret=1
grep "status: NOERROR" dig.out.2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to notimp edns server fails ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 ednsnotimp soa > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking refused edns server setup ($n)"
ret=0
$DIG $DIGOPTS +edns @10.53.0.10 ednsrefused soa > dig.out.1.test$n || ret=1
grep "status: REFUSED" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +noedns @10.53.0.10 ednsrefused soa > dig.out.2.test$n || ret=1
grep "status: NOERROR" dig.out.2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to refused edns server fails ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 ednsrefused soa > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking drop edns server setup ($n)"
ret=0
......@@ -34,10 +88,10 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to drop edns server succeeds ($n)"
echo_i "checking recursive lookup to drop edns server fails ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 dropedns soa > dig.out.test$n || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
$DIG $DIGOPTS +tcp @10.53.0.1 dropedns soa > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
......@@ -55,10 +109,10 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to drop edns + no tcp server succeeds ($n)"
echo_i "checking recursive lookup to drop edns + no tcp server fails ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 dropedns-notcp soa > dig.out.test$n || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
$DIG $DIGOPTS +tcp @10.53.0.1 dropedns-notcp soa > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
......@@ -135,10 +189,10 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking recursive lookup to edns 512 + no tcp server succeeds ($n)"
echo_i "checking recursive lookup to edns 512 + no tcp server fails ($n)"
ret=0
$DIG $DIGOPTS +tcp @10.53.0.1 edns512-notcp soa > dig.out.test$n || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
......
......@@ -195,14 +195,20 @@ sub start_server {
$command .= "-X named.lock ";
$command .= "-m record,size,mctx ";
$command .= "-T clienttest ";
$command .= "-T nosoa "
if (-e "$testdir/$server/named.nosoa");
$command .= "-T dropedns "
if (-e "$testdir/$server/named.dropedns");
$command .= "-T ednsformerr "
if (-e "$testdir/$server/named.ednsformerr");
$command .= "-T ednsnotimp "
if (-e "$testdir/$server/named.ednsnotimp");
$command .= "-T ednsrefused "
if (-e "$testdir/$server/named.ednsrefused");
$command .= "-T noaa "
if (-e "$testdir/$server/named.noaa");
$command .= "-T noedns "
if (-e "$testdir/$server/named.noedns");
$command .= "-T dropedns "
if (-e "$testdir/$server/named.dropedns");
$command .= "-T nosoa "
if (-e "$testdir/$server/named.nosoa");
$command .= "-T maxudp512 "
if (-e "$testdir/$server/named.maxudp512");
$command .= "-T maxudp1460 "
......
......@@ -17139,7 +17139,58 @@ allow-query { !{ !10/8; any; }; key example; };
source of hints and information that can be used to figure out
what went wrong and how to fix the problem.
</para>
</section>
<section><info><title>EDNS compliance issues</title></info>
<para>
EDNS (Extended DNS) is a standard that was first specified
in 1999. It is required for DNSSEC validation, DNS COOKIE
options, and other features. There are broken and outdated
DNS servers and firewalls still in use which misbehave when
queried with EDNS; for example, they may drop EDNS queries
rather than replying with FORMERR. BIND and other recursive
name servers have traditionally employed workarounds in this
situation, retrying queries in different ways and eventually
falling back to plain DNS queries without EDNS.
</para>
<para>
Such workarounds cause unnecessary resolution delays,
increase code complexity, and prevent deployment of new DNS
features. As of February 2019, all major DNS software vendors
have agreed to remove these workarounds; see
<link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="https://dnsflagday.net">https://dnsflagday.net</link>
for further details. This change was implemented in BIND
as of release 9.14.0.
</para>
<para>
As a result, some domains may be non-resolvable without manual
intervention. In these cases, resolution can be restored by
adding <command>server</command> clauses for the offending
servers, specifying <command>edns no</command> or
<command>send-cookie no</command>, depending on the specific
noncompliance.
</para>
<para>
To determine which <command>server</command> clause to use,
run the following commands to send queries to the authoritative
servers for the broken domain:
</para>
<literallayout>
dig soa &lt;zone&gt; @&lt;server&gt; +dnssec
dig soa &lt;zone&gt; @&lt;server&gt; +dnssec +nocookie
dig soa &lt;zone&gt; @&lt;server&gt; +noedns
</literallayout>
<para>
If the first command fails but the second succeeds, the
server most likely needs <command>send-cookie no</command>.
If the first two fail but the third succeeds, then the server
needs EDNS to be fully disabled with <command>edns no</command>.
</para>
<para>
Please contact the administrators of noncompliant domains
and encourage them to upgrade their broken DNS servers.
</para>
</section>
</section>
<section><info><title>Incrementing and Changing the Serial Number</title></info>
......
......@@ -156,6 +156,47 @@
<section xml:id="relnotes_removed"><info><title>Removed Features</title></info>
<itemizedlist>
<listitem>
<para>
Workarounds for servers that misbehave when queried with EDNS
have been removed, because these broken servers and the
workarounds for their noncompliance cause unnecessary delays,
increase code complexity, and prevent deployment of new DNS
features. See <link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="https://dnsflagday.net">https://dnsflagday.net</link>
for further details.
</para>
<para>
In particular, resolution will no longer fall back to
plain DNS when there was no response from an authoritative
server. This will cause some domains to become non-resolvable
without manual intervention. In these cases, resolution can
be restored by adding <command>server</command> clauses for the
offending servers, specifying <command>edns no</command> or
<command>send-cookie no</command>, depending on the specific
noncompliance.
</para>
<para>
To determine which <command>server</command> clause to use, run
the following commands to send queries to the authoritative
servers for the broken domain:
</para>
<literallayout>
dig soa &lt;zone&gt; @&lt;server&gt; +dnssec
dig soa &lt;zone&gt; @&lt;server&gt; +dnssec +nocookie
dig soa &lt;zone&gt; @&lt;server&gt; +noedns
</literallayout>
<para>
If the first command fails but the second succeeds, the
server most likely needs <command>send-cookie no</command>.
If the first two fail but the third succeeds, then the server
needs EDNS to be fully disabled with <command>edns no</command>.
</para>
<para>
Please contact the administrators of noncompliant domains
and encourage them to upgrade their broken DNS servers. [GL #150]
</para>
</listitem>
<listitem>
<para>
Previously, it was possible to build BIND without thread support
......
......@@ -2327,26 +2327,6 @@ issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
return (dns_view_issecuredomain(view, name, now, checknta, issecure));
}
static bool
wouldvalidate(fetchctx_t *fctx) {
bool secure_domain;
isc_result_t result;
isc_stdtime_t now;
if (!fctx->res->view->enablevalidation)
return (false);
if (fctx->res->view->dlv != NULL)
return (true);
isc_stdtime_get(&now);
result = dns_view_issecuredomain(fctx->res->view, &fctx->name,
now, true, &secure_domain);
if (result != ISC_R_SUCCESS)
return (false);
return (secure_domain);
}
static isc_result_t
resquery_send(resquery_t *query) {
fetchctx_t *fctx;
......@@ -2514,25 +2494,11 @@ resquery_send(resquery_t *query) {
if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) != 0)
query->options |= DNS_FETCHOPT_NOEDNS0;
/* See if response history indicates that EDNS is not supported. */
if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
dns_adb_noedns(fctx->adb, query->addrinfo))
query->options |= DNS_FETCHOPT_NOEDNS0;
if (fctx->timeout && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
isc_sockaddr_t *sockaddr = &query->addrinfo->sockaddr;
struct tried *tried;
if (fctx->timeouts > (MAX_EDNS0_TIMEOUTS * 2) &&
(!EDNSOK(query->addrinfo) || !wouldvalidate(fctx))) {
query->options |= DNS_FETCHOPT_NOEDNS0;
fctx->reason = "disabling EDNS";
} else if ((tried = triededns512(fctx, sockaddr)) != NULL &&
tried->count >= 2U &&
(!EDNSOK(query->addrinfo) || !wouldvalidate(fctx))) {
query->options |= DNS_FETCHOPT_NOEDNS0;
fctx->reason = "disabling EDNS";
} else if ((tried = triededns(fctx, sockaddr)) != NULL) {
if ((tried = triededns(fctx, sockaddr)) != NULL) {
if (tried->count == 1U) {
hint = dns_adb_getudpsize(fctx->adb,
query->addrinfo);
......@@ -2619,15 +2585,6 @@ resquery_send(resquery_t *query) {
ednsopts[ednsopt].value = NULL;
ednsopt++;
}
#if DNS_EDNS_VERSION > 0
/*
* Some EDNS(0) servers don't ignore unknown options
* as it was not a explict requirement of RFC 2671.
* Only send COOKIE to EDNS(1) servers.
*/
if (version < 1)
sendcookie = false;
#endif
if (sendcookie) {
INSIST(ednsopt < DNS_EDNSOPTIONS);
ednsopts[ednsopt].code = DNS_OPT_COOKIE;
......@@ -9402,7 +9359,6 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
resquery_t *query = rctx->query;
isc_buffer_t b;
char code[64];
unsigned char cookie[64];
if (fctx->rmessage->rcode == dns_rcode_noerror ||
fctx->rmessage->rcode == dns_rcode_yxdomain ||
......@@ -9423,24 +9379,7 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
" due to bad server", fctx->info);
fctx->qmin_labels = DNS_MAX_LABELS + 1;
result = rctx_answer_minimized(rctx);
} else if (!NOCOOKIE(query->addrinfo) &&
(fctx->rmessage->rcode == dns_rcode_formerr ||
fctx->rmessage->rcode == dns_rcode_notimp ||
fctx->rmessage->rcode == dns_rcode_refused) &&
dns_adb_getcookie(fctx->adb, query->addrinfo,