diff --git a/CHANGES b/CHANGES
index bd5de9e57d..4a4b8cfe34 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3593. [func] Update EDNS processing to better track remote server
+ capabilities. [RT #30655]
+
3592. [doc] Moved documentation of rndc command options to the
rndc man page. [RT #33506]
diff --git a/EDNS-9.10 b/EDNS-9.10
new file mode 100644
index 0000000000..a14ec50743
--- /dev/null
+++ b/EDNS-9.10
@@ -0,0 +1,31 @@
+
+ EDNS in BIND 9.10
+
+The EDNS code in BIND 9.10 records successful plain and EDNS query
+counts as well at timeouts for plain DNS and EDNS queries at various
+EDNS buffer sizes: 4096, 1432, 1232 and 512 for each server named
+talks to. A EDNS timeout for a lower buffer size is also counted
+against higher buffer sizes. These are held in 8 bit counters and
+are shifted on overflow of any counter. This will result in false
+positives due to transitory network problems to be removed from the
+history.
+
+The buffer sizes of 1432 and 1232 are choosen to allow for a IPv4/IPv6
+encapsulated UDP message to be sent without fragmentation at Ethernet
+and IPv6 network mimimum MTU sizes.
+
+Named also records the largest successful EDNS response size seen.
+
+When talking to a new server named will send a EDNS query advertising
+a 512 byte UDP buffer. This is the most conservative EDNS message
+that can be sent. If this results in a response with TC=1 being
+sent a larger EDNS buffer size will be used rather than a immediate
+fallback to TCP.
+
+If there are too many timeouts to EDNS queries without a successful EDNS
+query and with successful plain DNS queries named will fallback to using
+plain DNS when taking to a server. Named will periodically send a EDNS
+query to see if the server now supports EDNS.
+
+When talking to a server using EDNS named will choose a EDNS buffer size
+based on the history of EDNS timeouts at various advertised sizes.
diff --git a/bin/named/main.c b/bin/named/main.c
index 39efe3f92f..463703e2f7 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -419,7 +419,7 @@ parse_command_line(int argc, char *argv[]) {
isc_commandline_errprint = ISC_FALSE;
while ((ch = isc_commandline_parse(argc, argv,
- "46c:C:d:E:fFgi:lm:n:N:p:P:"
+ "46c:C:d:D:E:fFgi:lm:n:N:p:P:"
"sS:t:T:U:u:vVx:")) != -1) {
switch (ch) {
case '4':
@@ -455,6 +455,9 @@ parse_command_line(int argc, char *argv[]) {
ns_g_debuglevel = parse_int(isc_commandline_argument,
"debug level");
break;
+ case 'D':
+ /* Descriptive comment for 'ps'. */
+ break;
case 'E':
ns_g_engine = isc_commandline_argument;
break;
diff --git a/bin/named/named.docbook b/bin/named/named.docbook
index 1f08e196e0..16242f6899 100644
--- a/bin/named/named.docbook
+++ b/bin/named/named.docbook
@@ -62,6 +62,7 @@
+
@@ -149,6 +150,18 @@
+
+ -D string
+
+
+ Specifies a string that is used to identify a instance of
+ named in a process listing. The contents
+ of string are
+ not examined.
+
+
+
+
-E engine-name
diff --git a/bin/tests/bigtest/README b/bin/tests/bigtest/README
new file mode 100644
index 0000000000..eed30a6d05
--- /dev/null
+++ b/bin/tests/bigtest/README
@@ -0,0 +1,15 @@
+
+ bash buildzones.sh < zones # creates setup, run, servers/* master/*
+ # named.conf
+ sudo sh setup # configure interfaces
+ sh run # setup
+
+ ../named/named [-g] -c named.conf
+
+ sh tests.sh < zones
+
+ sudo sh teardown # teardown interfaces
+
+The test server can controlled with
+
+ rndc -k rndc.key -s 127.127.0.0 -p 5300
diff --git a/bin/tests/bigtest/buildzones.sh b/bin/tests/bigtest/buildzones.sh
new file mode 100644
index 0000000000..aabc3d877a
--- /dev/null
+++ b/bin/tests/bigtest/buildzones.sh
@@ -0,0 +1,257 @@
+#!/bin/bash
+
+TOP=$( (cd ../../.. && pwd) )
+
+addr=127.127.0.0
+ttl=300
+named=${TOP}/bin/named/named
+keygen=${TOP}/bin/dnssec/dnssec-keygen
+dsfromkey=${TOP}/bin/dnssec/dnssec-dsfromkey
+
+nextaddr() {
+ OLDIF="$IFS"
+ IFS="${IFS}."
+ set $1
+ IFS="$OLDIFS"
+ _a=$1 _b=$2 _c=$3 _d=$4
+ _d=$(($_d + 1))
+ case $_d in
+ 256) _c=$(($_c + 1)); _d=0;;
+ esac
+ case $_c in
+ 256) _b=$(($_b + 1)); _c=0;;
+ esac
+ echo $_a.$_b.$_c.$_d
+}
+
+parent() {
+ OLDIF="$IFS"
+ IFS="${IFS}."
+ set $1
+ IFS="$OLDIFS"
+ shift
+ while [ $# -ne 0 ]
+ do
+ printf %s ${1}
+ shift
+ printf %s ${1:+.}
+
+ done
+}
+
+blackhole() {
+ echo 'options {'
+ echo ' port 5300;'
+ echo " listen-on { $1; };"
+ echo " query-source $1;"
+ echo " notify-source $1;"
+ echo " transfer-source $1;"
+ echo ' key-directory "keys";'
+ echo " recursion ${2:-no};"
+ echo ' pid-file "pids/'"${addr}"'.pid";'
+ echo ' blackhole { 127.127.0.0; };'
+ echo '};'
+}
+
+refuse() {
+ echo 'options {'
+ echo ' port 5300;'
+ echo " listen-on { $1; };"
+ echo " query-source $1;"
+ echo " notify-source $1;"
+ echo " transfer-source $1;"
+ echo ' key-directory "keys";'
+ echo " recursion ${2:-no};"
+ echo ' pid-file "pids/'"${addr}"'.pid";'
+ echo ' allow-query { !127.127.0.0; any; };'
+ echo '};'
+}
+
+options() {
+ echo 'options {'
+ echo ' port 5300;'
+ echo " listen-on { $1; };"
+ echo " query-source $1;"
+ echo " notify-source $1;"
+ echo " transfer-source $1;"
+ echo ' key-directory "keys";'
+ echo " recursion ${2:-no};"
+ echo ' pid-file "pids/'"${addr}"'.pid";'
+ echo '};'
+}
+
+controls() {
+ echo 'include "rndc.key";'
+ echo "controls { inet $addr port 9953 allow { any; } keys { "rndc-key"; }; };"
+}
+
+delay() {
+ _s=$1
+ OLDIF="$IFS"
+ IFS="${IFS}/"
+ set ${2:-.}
+ IFS="$OLDIFS"
+
+ case $1 in
+ .) _d=;;
+ *) _d=$1;;
+ esac
+ case $_s in
+ 1) echo -T delay=${_d:-100};;
+ 2) echo -T delay=${2:-50};;
+ 3) echo -T delay=${3:-150};;
+ 4) echo -T delay=${4:-250};;
+ 5) echo -T delay=${5:-125};;
+ 6) echo -T delay=${6:-25};;
+ 7) echo -T delay=${7:-75};;
+ 8) echo -T delay=${8:-125};;
+ 9) echo -T delay=${9:-10};;
+ 10) echo -T delay=${10:-40};;
+ 11) echo -T delay=${11:-80};;
+ 12) echo -T delay=${12:-90};;
+ *) echo -T delay=50;;
+ esac
+}
+
+trusted-keys () {
+ awk '$3 == "DNSKEY" {
+ b = ""; for (i=7; i <= NF; i++) { b = b $i; };
+ print "trusted-keys { \""$1"\"",$4,$5,$6,"\""b"\"; };" };'
+}
+
+signed-zone () {
+ echo "zone "'"'"${1:-.}"'"'" {"
+ echo " type master;"
+ echo " file "'"'"master/${2}.db"'"'";"
+ echo " auto-dnssec maintain;"
+ echo " allow-update { any; };"
+ echo "};"
+}
+
+unsigned-zone () {
+ echo "zone "'"'"${1:-.}"'"'" {"
+ echo " type master;"
+ echo " file "'"'"master/${2}.db"'"'";"
+ echo "};"
+}
+
+slave-zone () {
+ echo "zone "'"'"${zone:-.}"'"'" {"
+ echo " type slave;"
+ echo " masters { ${master}; };"
+ echo "};"
+}
+
+rm -rf servers master keys setup teardown run
+mkdir -p servers
+mkdir -p master
+mkdir -p keys
+
+echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup
+echo "ifconfig lo0 $addr -alias" >> teardown
+controls $addr > named.conf
+options $addr yes >> named.conf
+echo 'zone "." { type hint; file "master/hint.db"; };' >> named.conf
+
+while read zone servers nsfmt signed delay blackhole refuse flags
+do
+ i=1
+ case "${zone}" in
+ .) file=root zone=;;
+ *) file="$zone";;
+ esac
+ if [ "${zone}" != "" ] ; then
+ p=$(parent $zone)
+ case "${p}" in
+ "") p=root;;
+ esac
+ else
+ p=hint
+ fi
+ #echo "zone='${zone}' parent='${p}'"
+ addr=$(nextaddr $addr)
+ ns=$(printf "$nsfmt" ${i} "${zone}")
+ d=$(delay $i ${delay:-.})
+
+ echo "${zone}. ${ttl} soa ${ns}. hostmaster.${zone}${zone:+.} 1 3600 1200 604800 1200" >> master/${file}.db
+ echo "${zone}. ${ttl} ns ${ns}." >> master/${file}.db
+ echo "${ns}. ${ttl} a ${addr}" >> master/${file}.db
+ echo "${zone}. ${ttl} ns ${ns}." >> master/${p}.db
+ echo "${ns}. ${ttl} a ${addr}" >> master/${p}.db
+ if [ $signed = "S" ]; then
+ kskkey=`${keygen} -K keys -f KSK ${zone:-.}`
+ zskkey=`${keygen} -K keys ${zone:-.}`
+ if [ "${zone}" != "" ] ; then
+ ${dsfromkey} -T ${ttl} keys/${kskkey}.key >> master/${p}.db
+ else
+ trusted-keys < keys/${kskkey}.key >> named.conf
+ fi
+ fi
+ echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup
+ echo "ifconfig lo0 $addr -alias" >> teardown
+ echo "${named} -D bigtest -c servers/${addr}.conf $d $flags" >> run
+ options ${addr} > servers/${addr}.conf
+ case ${signed} in
+ S) signed-zone ${zone:-.} ${file} >> servers/${addr}.conf;;
+ P) unsigned-zone ${zone:-.} ${file} >> servers/${addr}.conf;;
+ *) echo ${signed}; exit 1;;
+ esac
+
+ # slave servers
+ while [ $i -lt $servers ]
+ do
+ master=$addr
+ i=$(($i + 1))
+ ns=$(printf "$nsfmt" ${i} "${zone}")
+ d=$(delay $i ${delay:-.})
+ addr=$(nextaddr $addr)
+ echo "${zone}. ${ttl} ns ${ns}." >> master/${file}.db
+ echo "${ns}. ${ttl} a ${addr}" >> master/${file}.db
+ echo "${zone}. ${ttl} ns ${ns}." >> master/${p}.db
+ echo "${ns}. ${ttl} a ${addr}" >> master/${p}.db
+ echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup
+ echo "ifconfig lo0 $addr -alias" >> teardown
+ echo "${named} -D bigtest -c servers/${addr}.conf $d $flags" >> run
+ if [ $i = ${refuse:-.} ]
+ then
+ refuse $addr > servers/${addr}.conf
+ elif [ $i = ${blackhole:-.} ]
+ then
+ blackhole $addr > servers/${addr}.conf
+ else
+ options $addr > servers/${addr}.conf
+ fi
+ slave-zone ${zone:-.} ${master} >> servers/${addr}.conf
+ done
+ if [ "${zone}" != "" ] ; then
+ echo "www.${zone}. ${ttl} a 127.0.0.1" >> master/${file}.db
+ echo "www.${zone}. ${ttl} aaaa ::1" >> master/${file}.db
+ echo "${zone}. ${ttl} mx 10 mail.${zone}." >> master/${file}.db
+ echo "mail.${zone}. ${ttl} a 127.0.0.1" >> master/${file}.db
+ echo "mail.${zone}. ${ttl} aaaa ::1" >> master/${file}.db
+ echo "*.big.${zone}. ${ttl} txt (" >> master/${file}.db
+ i=0
+ while [ $i -lt 150 ]
+ do
+ echo "1234567890" >> master/${file}.db
+ i=$(($i + 1))
+ done
+ echo ")" >> master/${file}.db
+ echo "*.medium.${zone}. ${ttl} txt (" >> master/${file}.db
+ i=0
+ while [ $i -lt 120 ]
+ do
+ echo "1234567890" >> master/${file}.db
+ i=$(($i + 1))
+ done
+ echo ")" >> master/${file}.db
+ echo "*.medium.${zone}. ${ttl} txt (" >> master/${file}.db
+ i=0
+ while [ $i -lt 120 ]
+ do
+ echo "1234567890" >> master/${file}.db
+ i=$(($i + 1))
+ done
+ echo ")" >> master/${file}.db
+ fi
+done
diff --git a/bin/tests/bigtest/rndc.key b/bin/tests/bigtest/rndc.key
new file mode 100644
index 0000000000..f279e14c1a
--- /dev/null
+++ b/bin/tests/bigtest/rndc.key
@@ -0,0 +1,5 @@
+key "rndc-key" {
+ algorithm hmac-md5;
+ secret "xxxxxxxxxxxxxxxxxxxxHg==";
+};
+
diff --git a/bin/tests/bigtest/tests.sh b/bin/tests/bigtest/tests.sh
new file mode 100644
index 0000000000..4bdda3f982
--- /dev/null
+++ b/bin/tests/bigtest/tests.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+TOP=$( (cd ../../.. && pwd) )
+dig=${TOP}/bin/dig/dig
+
+cmd="${dig} -p 5300 @127.127.0.0 txt"
+inner() {
+ zone=$1 i=$2 to=$3
+ x=$i
+ dout=dig$x.out
+ tout=time$x.out
+ while [ $i -lt $to ]
+ do
+ case $zone in
+ .) zone=;;
+ esac
+
+ (time -p $cmd $i.${sub}$zone > $dout ) 2> $tout
+ s=`sed -n '/real/s/[^0-9]*\([0-9]*\)\..*/\1/p' $tout`
+ case $s in
+ 0);;
+ 1) t1=`expr ${t1:-0} + 1`;;
+ 2) t2=`expr ${t2:-0} + 1`;;
+ 3) t3=`expr ${t3:-0} + 1`;;
+ *) echo $i `grep real $tout`;;
+ esac
+
+ grep "status: \(NXDOMAIN\|NOERROR\)" $dout > /dev/null || {
+ echo $cmd $i.${sub}$zone
+ cat $dout
+ }
+ i=`expr $i + 1`
+ done
+ if test ${t1:-0} -ne 0 -o ${t2:-0} -ne 0 -o ${t3:-0} -ne 0
+ then
+ echo "$x timeouts: t1=${t1:-0} t2=${t2:-0} t3=${t3:-0}"
+ fi
+}
+
+while read zone rest
+do
+ for sub in "" medium. big.
+ do
+ case $zone in
+ .) echo doing ${sub:-.};;
+ *) echo doing $sub$zone;;
+ esac
+ ( inner $zone 1 100) &
+ ( inner $zone 101 200) &
+ ( inner $zone 201 300) &
+ ( inner $zone 301 400) &
+ ( inner $zone 401 500) &
+ ( inner $zone 501 600) &
+ ( inner $zone 601 700) &
+ ( inner $zone 701 800) &
+ ( inner $zone 801 900) &
+ ( inner $zone 901 1000) &
+ ( inner $zone 1001 1100) &
+ ( inner $zone 1101 1200) &
+ ( inner $zone 1201 1300) &
+ ( inner $zone 1301 1400) &
+ ( inner $zone 1401 1500) &
+ ( inner $zone 1501 1600) &
+ ( inner $zone 1601 1700) &
+ wait
+ done
+done
diff --git a/bin/tests/bigtest/zones b/bin/tests/bigtest/zones
new file mode 100644
index 0000000000..0bdcdfe23f
--- /dev/null
+++ b/bin/tests/bigtest/zones
@@ -0,0 +1,18 @@
+noedns-1.tld 1 ns%u.%s P . x x -T noedns
+dropedns-1.tld 1 ns%u.%s P . x x -T dropedns
+maxudp512-1.tld 1 ns%u.%s S . x x -T maxudp=512
+maxudp1460-1.tld 1 ns%u.%s S . x x -T maxudp=1460
+plain-1.tld 1 ns%u.%s S . x x
+noedns-3.tld 3 ns%u.%s P . 2 x -T noedns
+dropedns-3.tld 3 ns%u.%s P . 2 x -T dropedns
+maxudp512-3.tld 3 ns%u.%s S . x x -T maxudp=512
+maxudp1460-3.tld 3 ns%u.%s S . x x -T maxudp=1460
+plain-3.tld 3 ns%u.%s S . x 3
+noedns-5.tld 5 ns%u.%s P . 3 x -T noedns
+dropedns-5.tld 5 ns%u.%s P . x x -T dropedns
+maxudp512-5.tld 5 ns%u.%s S . x x -T maxudp=512
+maxudp1460-5.tld 5 ns%u.%s S . x x -T maxudp=1460
+400ms-1.tld 5 ns%u.%s S 400/400/400/400/400 2 x
+plain-5.tld 5 ns%u.%s S . x x
+tld 12 ns%u.%s S . 5 8
+. 12 ns%u.root-servers.nil%s S . x x
diff --git a/bin/tests/system/cacheclean/tests.sh b/bin/tests/system/cacheclean/tests.sh
index 9c7ed97e93..2f711b3d5e 100644
--- a/bin/tests/system/cacheclean/tests.sh
+++ b/bin/tests/system/cacheclean/tests.sh
@@ -94,8 +94,8 @@ echo "I:reset and check that records are correctly cached initially"
ret=0
load_cache
dump_cache
-nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | wc -l`
-[ $nrecords -eq 20 ] || ret=1
+nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | grep -w '\(TXT\|ANY\)'| wc -l`
+[ $nrecords -eq 17 ] || { ret=1; echo "I: found $nrecords records expected 17"; }
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
@@ -180,8 +180,8 @@ status=`expr $status + $ret`
echo "I:check the number of cached records remaining"
ret=0
dump_cache
-nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | wc -l`
-[ $nrecords -eq 19 ] || ret=1
+nrecords=`grep flushtest.example ns2/named_dump.db | grep -v '^;' | grep -w '\(TXT\|ANY\)' | wc -l`
+[ $nrecords -eq 17 ] || { ret=1; echo "I: found $nrecords records expected 17"; }
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
diff --git a/bin/tests/system/checknames/tests.sh b/bin/tests/system/checknames/tests.sh
index 2a45159b7c..566078a7b9 100644
--- a/bin/tests/system/checknames/tests.sh
+++ b/bin/tests/system/checknames/tests.sh
@@ -53,8 +53,8 @@ n=`expr $n + 1`
# Entry should exist
echo "I: check that 'check-names response warn;' works ($n)"
ret=0
-$DIG $DIGOPTS yy_yy.ignore.example. @10.53.0.1 a > dig.out.ns1.test$n || ret=1
-$DIG $DIGOPTS yy_yy.ignore.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+$DIG $DIGOPTS +noauth yy_yy.ignore.example. @10.53.0.1 a > dig.out.ns1.test$n || ret=1
+$DIG $DIGOPTS +noauth yy_yy.ignore.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns1.test$n dig.out.ns2.test$n || ret=1
grep "check-names warning yy_yy.ignore.example/A/IN" ns2/named.run > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh
index 57b9d67f48..839ff61666 100644
--- a/bin/tests/system/dnssec/tests.sh
+++ b/bin/tests/system/dnssec/tests.sh
@@ -76,6 +76,11 @@ israw1 () {
return $?
}
+# strip NS and RRSIG NS from input
+stripns () {
+ awk '($4 == "NS") || ($4 == "RRSIG" && $5 == "NS") { next} { print }' $1
+}
+
# Check the example. domain
echo "I:checking that zone transfer worked ($n)"
@@ -193,9 +198,13 @@ fi
echo "I:checking positive wildcard validation NSEC ($n)"
ret=0
-$DIG $DIGOPTS a.wild.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+$DIG $DIGOPTS a.wild.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
$DIG $DIGOPTS a.wild.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+$PERL ../digcomp.pl dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
+grep "\*\.wild\.example\..*RRSIG NSEC" dig.out.ns4.test$n > /dev/null || ret=1
+grep "\*\.wild\.example\..*NSEC z\.example" dig.out.ns4.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
@@ -235,7 +244,9 @@ echo "I:checking positive wildcard validation NSEC3 ($n)"
ret=0
$DIG $DIGOPTS a.wild.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
$DIG $DIGOPTS a.wild.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+$PERL ../digcomp.pl dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
@@ -259,7 +270,9 @@ $DIG $DIGOPTS a.wild.optout.example. \
@10.53.0.3 a > dig.out.ns3.test$n || ret=1
$DIG $DIGOPTS a.wild.optout.example. \
@10.53.0.4 a > dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+$PERL ../digcomp.pl dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
diff --git a/bin/tests/system/forward/tests.sh b/bin/tests/system/forward/tests.sh
index e9f587eead..f4bef088d3 100644
--- a/bin/tests/system/forward/tests.sh
+++ b/bin/tests/system/forward/tests.sh
@@ -27,56 +27,56 @@ status=0
echo "I:checking that a forward zone overrides global forwarders"
ret=0
-$DIG txt.example1. txt @$hidden -p 5300 > dig.out.hidden || ret=1
-$DIG txt.example1. txt @$f1 -p 5300 > dig.out.f1 || ret=1
+$DIG +noadd +noauth txt.example1. txt @$hidden -p 5300 > dig.out.hidden || ret=1
+$DIG +noadd +noauth txt.example1. txt @$f1 -p 5300 > dig.out.f1 || ret=1
$PERL ../digcomp.pl dig.out.hidden dig.out.f1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that a forward first zone no forwarders recurses"
ret=0
-$DIG txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
-$DIG txt.example2. txt @$f1 -p 5300 > dig.out.f1 || ret=1
+$DIG +noadd +noauth txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
+$DIG +noadd +noauth txt.example2. txt @$f1 -p 5300 > dig.out.f1 || ret=1
$PERL ../digcomp.pl dig.out.root dig.out.f1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that a forward only zone no forwarders fails"
ret=0
-$DIG txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
-$DIG txt.example2. txt @$f1 -p 5300 > dig.out.f1 || ret=1
+$DIG +noadd +noauth txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
+$DIG +noadd +noauth txt.example2. txt @$f1 -p 5300 > dig.out.f1 || ret=1
$PERL ../digcomp.pl dig.out.root dig.out.f1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that global forwarders work"
ret=0
-$DIG txt.example4. txt @$hidden -p 5300 > dig.out.hidden || ret=1
-$DIG txt.example4. txt @$f1 -p 5300 > dig.out.f1 || ret=1
+$DIG +noadd +noauth txt.example4. txt @$hidden -p 5300 > dig.out.hidden || ret=1
+$DIG +noadd +noauth txt.example4. txt @$f1 -p 5300 > dig.out.f1 || ret=1
$PERL ../digcomp.pl dig.out.hidden dig.out.f1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that a forward zone works"
ret=0
-$DIG txt.example1. txt @$hidden -p 5300 > dig.out.hidden || ret=1
-$DIG txt.example1. txt @$f2 -p 5300 > dig.out.f2 || ret=1
+$DIG +noadd +noauth txt.example1. txt @$hidden -p 5300 > dig.out.hidden || ret=1
+$DIG +noadd +noauth txt.example1. txt @$f2 -p 5300 > dig.out.f2 || ret=1
$PERL ../digcomp.pl dig.out.hidden dig.out.f2 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that forwarding doesn't spontaneously happen"
ret=0
-$DIG txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
-$DIG txt.example2. txt @$f2 -p 5300 > dig.out.f2 || ret=1
+$DIG +noadd +noauth txt.example2. txt @$root -p 5300 > dig.out.root || ret=1
+$DIG +noadd +noauth txt.example2. txt @$f2 -p 5300 > dig.out.f2 || ret=1
$PERL ../digcomp.pl dig.out.root dig.out.f2 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking that a forward zone with no specified policy works"
ret=0
-$DIG txt.example3. txt @$hidden -p 5300 > dig.out.hidden || ret=1
-$DIG txt.example3. txt @$f2 -p 5300 > dig.out.f2 || ret=1
+$DIG +noadd +noauth txt.example3. txt @$hidden -p 5300 > dig.out.hidden || ret=1
+$DIG +noadd +noauth txt.example3. txt @$f2 -p 5300 > dig.out.f2 || ret=1
$PERL ../digcomp.pl dig.out.hidden dig.out.f2 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
diff --git a/bin/tests/system/lwresd/lwtest.c b/bin/tests/system/lwresd/lwtest.c
index 0d415eab09..5f05c43712 100644
--- a/bin/tests/system/lwresd/lwtest.c
+++ b/bin/tests/system/lwresd/lwtest.c
@@ -764,6 +764,7 @@ main(void) {
test_getrrsetbyname("a.example1.", 1, 1, 1, 0, 1);
test_getrrsetbyname("e.example1.", 1, 1, 1, 1, 1);
test_getrrsetbyname("e.example1.", 1, 255, 1, 1, 0);
+ test_getrrsetbyname("e.example1.", 1, 2, 1, 1, 1);
test_getrrsetbyname("e.example1.", 1, 46, 2, 0, 1);
test_getrrsetbyname("", 1, 1, 0, 0, 0);
diff --git a/bin/tests/system/org.isc.bind.system b/bin/tests/system/org.isc.bind.system
index 9d66b63295..47e6aec1ba 100644
--- a/bin/tests/system/org.isc.bind.system
+++ b/bin/tests/system/org.isc.bind.system
@@ -16,7 +16,7 @@
# $Id: org.isc.bind.system,v 1.1 2010/08/25 04:51:51 marka Exp $
-for ns in 1 2 3 4 5 6 7
+for ns in 1 2 3 4 5 6 7 8
do
/sbin/ifconfig lo0 10.53.0.$ns alias
/sbin/ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
diff --git a/bin/tests/system/start.pl b/bin/tests/system/start.pl
index 7b9cf1d159..319b31f66d 100644
--- a/bin/tests/system/start.pl
+++ b/bin/tests/system/start.pl
@@ -155,12 +155,21 @@ sub start_server {
close FH;
$command .= "$options";
} else {
+ $command .= "-D $server ";
$command .= "-m record,size,mctx ";
$command .= "-T clienttest ";
$command .= "-T nosoa "
if (-e "$testdir/$server/named.nosoa");
$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 maxudp512 "
+ if (-e "$testdir/$server/named.maxudp512");
+ $command .= "-T maxudp1460 "
+ if (-e "$testdir/$server/named.maxudp1460");
$command .= "-c named.conf -d 99 -g -U 4 ";
}
if ($restart) {
diff --git a/bin/tests/system/staticstub/knowngood.dig.out.rec b/bin/tests/system/staticstub/knowngood.dig.out.rec
index 15f84561a8..e854082c56 100644
--- a/bin/tests/system/staticstub/knowngood.dig.out.rec
+++ b/bin/tests/system/staticstub/knowngood.dig.out.rec
@@ -11,9 +11,6 @@
;; ANSWER SECTION:
data.example. 5M IN TXT "some" "test" "data"
-;; AUTHORITY SECTION:
-example. 5M IN NS ns4.example.
-
;; Total query time: 8 msec
;; FROM: draco to SERVER: 10.53.0.3
;; WHEN: Wed Jun 21 10:58:54 2000
diff --git a/bin/tests/system/staticstub/tests.sh b/bin/tests/system/staticstub/tests.sh
index 0d05558740..33d4d95cba 100755
--- a/bin/tests/system/staticstub/tests.sh
+++ b/bin/tests/system/staticstub/tests.sh
@@ -80,7 +80,7 @@ status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:look for static-stub zone data with recursion (should be found) ($n)"
ret=0
-$DIG +tcp data.example. @10.53.0.2 txt -p 5300 > dig.out.ns2.test$n || ret=1
+$DIG +tcp +noauth data.example. @10.53.0.2 txt -p 5300 > dig.out.ns2.test$n || ret=1
$PERL ../digcomp.pl knowngood.dig.out.rec dig.out.ns2.test$n || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
diff --git a/bin/tests/system/stub/knowngood.dig.out.rec b/bin/tests/system/stub/knowngood.dig.out.rec
index 9f2e4ee8e8..8ea19680d7 100644
--- a/bin/tests/system/stub/knowngood.dig.out.rec
+++ b/bin/tests/system/stub/knowngood.dig.out.rec
@@ -11,12 +11,6 @@
;; ANSWER SECTION:
data.child.example. 5M IN TXT "some" "test" "data"
-;; AUTHORITY SECTION:
-child.example. 5M IN NS ns2.child.example.
-
-;; ADDITIONAL SECTION:
-ns2.child.example. 5M IN A 10.53.0.2
-
;; Total query time: 8 msec
;; FROM: draco to SERVER: 10.53.0.3
;; WHEN: Wed Jun 21 10:58:54 2000
diff --git a/bin/tests/system/stub/tests.sh b/bin/tests/system/stub/tests.sh
index 72d81a5ea8..c379aba42b 100644
--- a/bin/tests/system/stub/tests.sh
+++ b/bin/tests/system/stub/tests.sh
@@ -53,7 +53,7 @@ $PERL ../digcomp.pl knowngood.dig.out.norec dig.out.ns3 || ret=1
echo "I:look for stub zone data with recursion (should be found) (pass=$pass)"
ret=0
-$DIG +tcp data.child.example. @10.53.0.3 txt -p 5300 > dig.out.ns3 || ret=1
+$DIG +tcp +noauth +noadd data.child.example. @10.53.0.3 txt -p 5300 > dig.out.ns3 || ret=1
$PERL ../digcomp.pl knowngood.dig.out.rec dig.out.ns3 || ret=1
[ $ret = 0 ] || { status=1; echo "I:failed"; }
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
index c5c14e5de9..77e637324f 100644
--- a/lib/dns/adb.c
+++ b/lib/dns/adb.c
@@ -242,6 +242,18 @@ struct dns_adbentry {
unsigned int flags;
unsigned int srtt;
+ isc_uint16_t udpsize;
+ unsigned char plain;
+ unsigned char plainto;
+ unsigned char edns;
+ unsigned char to4096; /* Our max. */
+ /*
+ * Allow for encapsulated IPv4/IPv6 UDP packet over ethernet.
+ * Ethernet 1500 - IP(20) - IP6(40) - UDP(8) = 1432.
+ */
+ unsigned char to1432; /* Ethernet */
+ unsigned char to1232; /* IPv6 nofrag */
+ unsigned char to512; /* plain DNS */
isc_sockaddr_t sockaddr;
isc_stdtime_t expires;
@@ -255,7 +267,6 @@ struct dns_adbentry {
ISC_LIST(dns_adblameinfo_t) lameinfo;
ISC_LINK(dns_adbentry_t) plink;
-
};
/*
@@ -952,12 +963,14 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
adbname->expire_v4, now + rdataset->ttl);
adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
- now + rdataset->ttl);
+ ISC_MIN(now + ADB_ENTRY_WINDOW,
+ now + rdataset->ttl));
} else {
DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
adbname->expire_v6, now + rdataset->ttl);
adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
- now + rdataset->ttl);
+ ISC_MIN(now + ADB_ENTRY_WINDOW,
+ now + rdataset->ttl));
}
if (new_addresses_added) {
@@ -1781,6 +1794,14 @@ new_adbentry(dns_adb_t *adb) {
e->lock_bucket = DNS_ADB_INVALIDBUCKET;
e->refcnt = 0;
e->flags = 0;
+ e->udpsize = 0;
+ e->edns = 0;
+ e->plain = 0;
+ e->plainto = 0;
+ e->to4096 = 0;
+ e->to1432 = 0;
+ e->to1232 = 0;
+ e->to512 = 0;
isc_random_get(&r);
e->srtt = (r & 0x1f) + 1;
e->expires = 0;
@@ -2043,6 +2064,7 @@ find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
entry_next = ISC_LIST_NEXT(entry, plink);
(void)check_expire_entry(adb, &entry, now);
if (entry != NULL &&
+ (entry->expires == 0 || entry->expires > now) &&
isc_sockaddr_equal(addr, &entry->sockaddr)) {
ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
@@ -2815,6 +2837,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
unsigned int wanted_addresses;
unsigned int wanted_fetches;
unsigned int query_pending;
+ char namebuf[DNS_NAME_FORMATSIZE];
REQUIRE(DNS_ADB_VALID(adb));
if (task != NULL) {
@@ -2875,6 +2898,11 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
REQUIRE(task != NULL);
}
+ if (isc_log_wouldlog(dns_lctx, DEF_LEVEL))
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ else
+ namebuf[0] = 0;
+
/*
* Try to see if we know anything about this name at all.
*/
@@ -2932,8 +2960,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
* Yes, it is.
*/
DP(DEF_LEVEL,
- "dns_adb_createfind: name %p is an alias (cached)",
- adbname);
+ "dns_adb_createfind: name %s (%p) is an alias (cached)",
+ namebuf, adbname);
alias = ISC_TRUE;
goto post_copy;
}
@@ -2948,8 +2976,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
result = dbfind_name(adbname, now, dns_rdatatype_a);
if (result == ISC_R_SUCCESS) {
DP(DEF_LEVEL,
- "dns_adb_createfind: found A for name %p in db",
- adbname);
+ "dns_adb_createfind: found A for name %s (%p) in db",
+ namebuf, adbname);
goto v6;
}
@@ -2958,8 +2986,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
*/
if (result == DNS_R_ALIAS) {
DP(DEF_LEVEL,
- "dns_adb_createfind: name %p is an alias",
- adbname);
+ "dns_adb_createfind: name %s (%p) is an alias",
+ namebuf, adbname);
alias = ISC_TRUE;
goto post_copy;
}
@@ -2988,8 +3016,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
if (result == ISC_R_SUCCESS) {
DP(DEF_LEVEL,
- "dns_adb_createfind: found AAAA for name %p",
- adbname);
+ "dns_adb_createfind: found AAAA for name %s (%p)",
+ namebuf, adbname);
goto fetch;
}
@@ -2998,8 +3026,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
*/
if (result == DNS_R_ALIAS) {
DP(DEF_LEVEL,
- "dns_adb_createfind: name %p is an alias",
- adbname);
+ "dns_adb_createfind: name %s (%p) is an alias",
+ namebuf, adbname);
alias = ISC_TRUE;
goto post_copy;
}
@@ -3039,9 +3067,9 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
if (WANT_INET(wanted_fetches) &&
fetch_name(adbname, start_at_zone,
dns_rdatatype_a) == ISC_R_SUCCESS) {
- DP(DEF_LEVEL,
- "dns_adb_createfind: started A fetch for name %p",
- adbname);
+ DP(DEF_LEVEL, "dns_adb_createfind: "
+ "started A fetch for name %s (%p)",
+ namebuf, adbname);
}
/*
@@ -3050,10 +3078,9 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
if (WANT_INET6(wanted_fetches) &&
fetch_name(adbname, start_at_zone,
dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
- DP(DEF_LEVEL,
- "dns_adb_createfind: "
- "started AAAA fetch for name %p",
- adbname);
+ DP(DEF_LEVEL, "dns_adb_createfind: "
+ "started AAAA fetch for name %s (%p)",
+ namebuf, adbname);
}
}
@@ -3389,8 +3416,12 @@ dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
if (debug)
fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
- fprintf(f, ";\t%s [srtt %u] [flags %08x]",
- addrbuf, entry->srtt, entry->flags);
+ fprintf(f, ";\t%s [srtt %u] [flags %08x] [edns %u/%u/%u/%u/%u] "
+ "[plain %u/%u]", addrbuf, entry->srtt, entry->flags,
+ entry->edns, entry->to4096, entry->to1432, entry->to1232,
+ entry->to512, entry->plain, entry->plainto);
+ if (entry->udpsize != 0U)
+ fprintf(f, " [udpsize %u]", entry->udpsize);
if (entry->expires != 0)
fprintf(f, " [ttl %d]", entry->expires - now);
fprintf(f, "\n");
@@ -3949,7 +3980,7 @@ dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
unsigned int rtt, unsigned int factor)
{
int bucket;
- unsigned int new_srtt;
+ isc_uint64_t new_srtt;
isc_stdtime_t now;
REQUIRE(DNS_ADB_VALID(adb));
@@ -3959,9 +3990,13 @@ dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
bucket = addr->entry->lock_bucket;
LOCK(&adb->entrylocks[bucket]);
- if (factor == DNS_ADB_RTTADJAGE)
- new_srtt = addr->entry->srtt * 98 / 100;
- else
+
+ if (factor == DNS_ADB_RTTADJAGE) {
+ new_srtt = addr->entry->srtt;
+ new_srtt <<= 9;
+ new_srtt -= addr->entry->srtt;
+ new_srtt >>= 9;
+ } else
new_srtt = (addr->entry->srtt / 10 * factor)
+ (rtt / 10 * (10 - factor));
@@ -4004,6 +4039,206 @@ dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
UNLOCK(&adb->entrylocks[bucket]);
}
+#define EDNSTOS 3U
+isc_boolean_t
+dns_adb_noedns(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
+ int bucket;
+ isc_boolean_t noedns = ISC_FALSE;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ if (addr->entry->edns == 0U &&
+ (addr->entry->plain > EDNSTOS || addr->entry->to4096 > EDNSTOS)) {
+ if (((addr->entry->plain + addr->entry->to4096) & 0x3f) != 0) {
+ noedns = ISC_TRUE;
+ } else {
+ /*
+ * Increment plain so we don't get stuck.
+ */
+ addr->entry->plain++;
+ if (addr->entry->plain == 0xff) {
+ addr->entry->edns >>= 1;
+ addr->entry->to4096 >>= 1;
+ addr->entry->to1432 >>= 1;
+ addr->entry->to1232 >>= 1;
+ addr->entry->to512 >>= 1;
+ addr->entry->plain >>= 1;
+ addr->entry->plainto >>= 1;
+ }
+ }
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+ return (noedns);
+}
+
+void
+dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
+ int bucket;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ addr->entry->plain++;
+ if (addr->entry->plain == 0xff) {
+ addr->entry->edns >>= 1;
+ addr->entry->to4096 >>= 1;
+ addr->entry->to1432 >>= 1;
+ addr->entry->to1232 >>= 1;
+ addr->entry->to512 >>= 1;
+ addr->entry->plain >>= 1;
+ addr->entry->plainto >>= 1;
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+void
+dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
+ int bucket;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ /*
+ * If we have not had a successful query then clear all
+ * edns timeout information.
+ */
+ if (addr->entry->edns == 0 && addr->entry->plain == 0) {
+ addr->entry->to512 = 0;
+ addr->entry->to1232 = 0;
+ addr->entry->to1432 = 0;
+ addr->entry->to4096 = 0;
+ } else {
+ addr->entry->to512 >>= 1;
+ addr->entry->to1232 >>= 1;
+ addr->entry->to1432 >>= 1;
+ addr->entry->to4096 >>= 1;
+ }
+ addr->entry->plainto++;
+ if (addr->entry->plainto == 0xff) {
+ addr->entry->edns >>= 1;
+ addr->entry->plain >>= 1;
+ addr->entry->plainto >>= 1;
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+void
+dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
+ int bucket;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ if (size <= 512U) {
+ if (addr->entry->to512 <= EDNSTOS) {
+ addr->entry->to512++;
+ addr->entry->to1232++;
+ addr->entry->to1432++;
+ addr->entry->to4096++;
+ }
+ } else if (size <= 1232U) {
+ if (addr->entry->to1232 <= EDNSTOS) {
+ addr->entry->to1232++;
+ addr->entry->to1432++;
+ addr->entry->to4096++;
+ }
+ } else if (size <= 1432U) {
+ if (addr->entry->to1432 <= EDNSTOS) {
+ addr->entry->to1432++;
+ addr->entry->to4096++;
+ }
+ } else {
+ if (addr->entry->to4096 <= EDNSTOS)
+ addr->entry->to4096++;
+ }
+
+ if (addr->entry->to4096 == 0xff) {
+ addr->entry->edns >>= 1;
+ addr->entry->to4096 >>= 1;
+ addr->entry->to1432 >>= 1;
+ addr->entry->to1232 >>= 1;
+ addr->entry->to512 >>= 1;
+ addr->entry->plain >>= 1;
+ addr->entry->plainto >>= 1;
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+void
+dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
+ int bucket;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ if (size < 512U)
+ size = 512U;
+ if (size > addr->entry->udpsize)
+ addr->entry->udpsize = size;
+ addr->entry->edns++;
+ if (addr->entry->edns == 0xff) {
+ addr->entry->edns >>= 1;
+ addr->entry->to4096 >>= 1;
+ addr->entry->to1432 >>= 1;
+ addr->entry->to1232 >>= 1;
+ addr->entry->to512 >>= 1;
+ addr->entry->plain >>= 1;
+ addr->entry->plainto >>= 1;
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+unsigned int
+dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
+ int bucket;
+ unsigned int size;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ size = addr->entry->udpsize;
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ return (size);
+}
+
+unsigned int
+dns_adb_probesize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
+ int bucket;
+ unsigned int size;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ if (addr->entry->to1232 > EDNSTOS)
+ size = 512;
+ else if (addr->entry->to1432 > EDNSTOS)
+ size = 1232;
+ else if (addr->entry->to4096 > EDNSTOS)
+ size = 1432;
+ else
+ size = 4096;
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ return (size);
+}
+
isc_result_t
dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h
index 92a46d4ba2..27ad144311 100644
--- a/lib/dns/include/dns/adb.h
+++ b/lib/dns/include/dns/adb.h
@@ -567,6 +567,93 @@ dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
*\li addr be valid.
*/
+void
+dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size);
+/*%
+ * Update seen UDP response size. The largest seen will be returned by
+ * dns_adb_getudpsize().
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+unsigned int
+dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr);
+/*%
+ * Return the largest seen UDP response size.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+unsigned int
+dns_adb_probesize(dns_adb_t *adb, dns_adbaddrinfo_t *addr);
+/*%
+ * Return suggested EDNS UDP size based on observed responses / failures.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+void
+dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr);
+/*%
+ * Record a successful plain DNS response.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+void
+dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr);
+/*%
+ * Record a plain DNS UDP query failed.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+void
+dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size);
+/*%
+ * Record a failed EDNS UDP response and the advertised EDNS UDP buffer size
+ * used.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+isc_boolean_t
+dns_adb_noedns(dns_adb_t *adb, dns_adbaddrinfo_t *addr);
+/*%
+ * Return whether EDNS should be disabled for this server.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+
isc_result_t
dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
dns_adbaddrinfo_t **addrp, isc_stdtime_t now);
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 58f9ef0e41..ec36115eb2 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -167,9 +167,16 @@ typedef struct query {
unsigned int attributes;
unsigned int sends;
unsigned int connects;
+ unsigned int udpsize;
unsigned char data[512];
} resquery_t;
+struct tried {
+ isc_sockaddr_t addr;
+ unsigned int count;
+ ISC_LINK(struct tried) link;
+};
+
#define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!')
#define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC)
@@ -231,8 +238,8 @@ struct fetchctx {
dns_forwarderlist_t forwarders;
dns_fwdpolicy_t fwdpolicy;
isc_sockaddrlist_t bad;
- isc_sockaddrlist_t edns;
- isc_sockaddrlist_t edns512;
+ ISC_LIST(struct tried) edns;
+ ISC_LIST(struct tried) edns512;
isc_sockaddrlist_t bad_edns;
dns_validator_t *validator;
ISC_LIST(dns_validator_t) validators;
@@ -452,6 +459,8 @@ struct dns_resolver {
#define FCTX_ADDRINFO_MARK 0x0001
#define FCTX_ADDRINFO_FORWARDER 0x1000
#define FCTX_ADDRINFO_TRIED 0x2000
+#define FCTX_ADDRINFO_EDNSOK 0x4000
+
#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
== 0)
#define ISFORWARDER(a) (((a)->flags & \
@@ -811,6 +820,10 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
query->attributes |= RESQUERY_ATTR_CANCELED;
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_format(&query->addrinfo->sockaddr,
+ addrbuf, sizeof(addrbuf));
+
/*
* Should we update the RTT?
*/
@@ -844,14 +857,45 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
inc_stats(fctx->res,
dns_resstatscounter_queryrtt5);
}
- } else {
+ } else {
+ isc_uint32_t value;
+ isc_uint32_t mask;
/*
* We don't have an RTT for this query. Maybe the
* packet was lost, or maybe this server is very
* slow. We don't know. Increase the RTT.
*/
INSIST(no_response);
- rtt = query->addrinfo->srtt + 200000;
+ isc_random_get(&value);
+ if (query->addrinfo->srtt > 800000)
+ mask = 0x3fff;
+ else if (query->addrinfo->srtt > 400000)
+ mask = 0x7fff;
+ else if (query->addrinfo->srtt > 200000)
+ mask = 0xffff;
+ else if (query->addrinfo->srtt > 100000)
+ mask = 0x1ffff;
+ else if (query->addrinfo->srtt > 50000)
+ mask = 0x3ffff;
+ else if (query->addrinfo->srtt > 25000)
+ mask = 0x7ffff;
+ else
+ mask = 0xfffff;
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
+ dns_adb_ednsto(fctx->adb, query->addrinfo,
+ query->udpsize);
+ else
+ dns_adb_timeout(fctx->adb, query->addrinfo);
+
+ /*
+ * Don't adjust timeout on EDNS queries unless we have
+ * seen a EDNS response.
+ */
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ (query->addrinfo->flags & FCTX_ADDRINFO_EDNSOK) == 0) {
+ mask >>= 2;
+ }
+ rtt = query->addrinfo->srtt + (value & mask);
if (rtt > MAX_SINGLE_QUERY_TIMEOUT_US)
rtt = MAX_SINGLE_QUERY_TIMEOUT_US;
/*
@@ -1618,62 +1662,70 @@ add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
ISC_LIST_INITANDAPPEND(fctx->bad_edns, sa, link);
}
-static isc_boolean_t
+static struct tried *
triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
- isc_sockaddr_t *sa;
+ struct tried *tried;
- for (sa = ISC_LIST_HEAD(fctx->edns);
- sa != NULL;
- sa = ISC_LIST_NEXT(sa, link)) {
- if (isc_sockaddr_equal(sa, address))
- return (ISC_TRUE);
+ for (tried = ISC_LIST_HEAD(fctx->edns);
+ tried != NULL;
+ tried = ISC_LIST_NEXT(tried, link)) {
+ if (isc_sockaddr_equal(&tried->addr, address))
+ return (tried);
}
- return (ISC_FALSE);
+ return (NULL);
}
static void
add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
- isc_sockaddr_t *sa;
+ struct tried *tried;
- if (triededns(fctx, address))
+ tried = triededns(fctx, address);
+ if (tried != NULL) {
+ tried->count++;
return;
-
- sa = isc_mem_get(fctx->mctx, sizeof(*sa));
- if (sa == NULL)
- return;
-
- *sa = *address;
- ISC_LIST_INITANDAPPEND(fctx->edns, sa, link);
-}
-
-static isc_boolean_t
-triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
- isc_sockaddr_t *sa;
-
- for (sa = ISC_LIST_HEAD(fctx->edns512);
- sa != NULL;
- sa = ISC_LIST_NEXT(sa, link)) {
- if (isc_sockaddr_equal(sa, address))
- return (ISC_TRUE);
}
- return (ISC_FALSE);
+ tried = isc_mem_get(fctx->mctx, sizeof(*tried));
+ if (tried == NULL)
+ return;
+
+ tried->addr = *address;
+ tried->count = 1;
+ ISC_LIST_INITANDAPPEND(fctx->edns, tried, link);
+}
+
+static struct tried *
+triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ struct tried *tried;
+
+ for (tried = ISC_LIST_HEAD(fctx->edns512);
+ tried != NULL;
+ tried = ISC_LIST_NEXT(tried, link)) {
+ if (isc_sockaddr_equal(&tried->addr, address))
+ return (tried);
+ }
+
+ return (NULL);
}
static void
add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
- isc_sockaddr_t *sa;
+ struct tried *tried;
- if (triededns512(fctx, address))
+ tried = triededns512(fctx, address);
+ if (tried != NULL) {
+ tried->count++;
+ return;
+ }
+
+ tried = isc_mem_get(fctx->mctx, sizeof(*tried));
+ if (tried == NULL)
return;
- sa = isc_mem_get(fctx->mctx, sizeof(*sa));
- if (sa == NULL)
- return;
-
- *sa = *address;
- ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link);
+ tried->addr = *address;
+ tried->count = 1;
+ ISC_LIST_INITANDAPPEND(fctx->edns512, tried, link);
}
static isc_result_t
@@ -1699,6 +1751,11 @@ resquery_send(resquery_t *query) {
isc_boolean_t connecting = ISC_FALSE;
dns_ednsopt_t ednsopts[EDNSOPTS];
unsigned ednsopt = 0;
+ isc_uint16_t hint = 0, udpsize = 0; /* No EDNS */
+
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_format(&query->addrinfo->sockaddr,
+ addrbuf, sizeof(addrbuf));
fctx = query->fctx;
QTRACE("send");
@@ -1766,11 +1823,12 @@ resquery_send(resquery_t *query) {
/*
* Set CD if the client says don't validate or the question is
- * under a secure entry point.
+ * under a secure entry point and it is not a recursive query.
*/
if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) {
fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
- } else if (res->view->enablevalidation) {
+ } else if (res->view->enablevalidation &&
+ (fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0) {
result = dns_view_issecuredomain(res->view, &fctx->name,
&secure_domain);
if (result != ISC_R_SUCCESS)
@@ -1827,35 +1885,37 @@ resquery_send(resquery_t *query) {
if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) != 0)
query->options |= DNS_FETCHOPT_NOEDNS0;
- /*
- * Handle timeouts by reducing the UDP response size to 512 bytes
- * then if that doesn't work disabling EDNS (includes DO) and CD.
- *
- * These timeout can be due to:
- * * broken nameservers that don't respond to EDNS queries.
- * * broken/misconfigured firewalls and NAT implementations
- * that don't handle IP fragmentation.
- * * broken/misconfigured firewalls that don't handle responses
- * greater than 512 bytes.
- * * broken/misconfigured firewalls that don't handle EDNS, DO
- * or CD.
- * * packet loss / link outage.
- */
- if (fctx->timeout) {
- if ((triededns512(fctx, &query->addrinfo->sockaddr) ||
- fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) &&
- (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ /* 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) &&
+ (query->addrinfo->flags & FCTX_ADDRINFO_EDNSOK) == 0) {
query->options |= DNS_FETCHOPT_NOEDNS0;
fctx->reason = "disabling EDNS";
- } else if ((triededns(fctx, &query->addrinfo->sockaddr) ||
- fctx->timeouts >= MAX_EDNS0_TIMEOUTS) &&
- (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
- query->options |= DNS_FETCHOPT_EDNS512;
- fctx->reason = "reducing the advertised EDNS UDP "
- "packet size to 512 octets";
+ } else if ((tried = triededns512(fctx, sockaddr)) != NULL &&
+ tried->count >= 2U &&
+ (query->addrinfo->flags & FCTX_ADDRINFO_EDNSOK) == 0) {
+ query->options |= DNS_FETCHOPT_NOEDNS0;
+ fctx->reason = "disabling EDNS";
+ } else if ((tried = triededns(fctx, sockaddr)) != NULL) {
+ if (tried->count == 1U) {
+ hint = dns_adb_getudpsize(fctx->adb,
+ query->addrinfo);
+ } else if (tried->count >= 2U) {
+ query->options |= DNS_FETCHOPT_EDNS512;
+ fctx->reason = "reducing the advertised EDNS "
+ "UDP packet size to 512 octets";
+ }
}
- fctx->timeout = ISC_FALSE;
}
+ fctx->timeout = ISC_FALSE;
/*
* Use EDNS0, unless the caller doesn't want it, or we know that
@@ -1864,19 +1924,46 @@ resquery_send(resquery_t *query) {
if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
unsigned int version = 0; /* Default version. */
- unsigned int flags;
- isc_uint16_t udpsize = res->udpsize;
+ unsigned int flags = query->addrinfo->flags;
isc_boolean_t reqnsid = res->view->requestnsid;
- flags = query->addrinfo->flags;
+ if ((flags & FCTX_ADDRINFO_EDNSOK) != 0 &&
+ (query->options & DNS_FETCHOPT_EDNS512) == 0) {
+ udpsize = dns_adb_probesize(fctx->adb,
+ query->addrinfo);
+ if (udpsize > res->udpsize)
+ udpsize = res->udpsize;
+ }
+
+ if (peer != NULL)
+ (void)dns_peer_getudpsize(peer, &udpsize);
+
+ if (udpsize == 0U && res->udpsize == 512U)
+ udpsize = 512;
+
+ /*
+ * Was the size forced to 512 in the configuration?
+ */
+ if (udpsize == 512U)
+ query->options |= DNS_FETCHOPT_EDNS512;
+
+ /*
+ * We have talked to this server before.
+ */
+ if (hint != 0U)
+ udpsize = hint;
+
+ /*
+ * We know nothing about the peer's capabilities
+ * so start with minimal EDNS UDP size.
+ */
+ if (udpsize == 0U)
+ udpsize = 512;
+
if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) {
version = flags & DNS_FETCHOPT_EDNSVERSIONMASK;
version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT;
}
- if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
- udpsize = 512;
- else if (peer != NULL)
- (void)dns_peer_getudpsize(peer, &udpsize);
/* request NSID for current view or peer? */
if (peer != NULL)
@@ -1899,6 +1986,7 @@ resquery_send(resquery_t *query) {
* bit.
*/
query->options |= DNS_FETCHOPT_NOEDNS0;
+ udpsize = 0;
}
} else {
/*
@@ -1910,6 +1998,11 @@ resquery_send(resquery_t *query) {
}
}
+ /*
+ * Record the UDP EDNS size choosen.
+ */
+ query->udpsize = udpsize;
+
/*
* If we need EDNS0 to do this query and aren't using it, we lose.
*/
@@ -1918,10 +2011,10 @@ resquery_send(resquery_t *query) {
goto cleanup_message;
}
- if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
+ if (udpsize > 512U)
add_triededns(fctx, &query->addrinfo->sockaddr);
- if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
+ if (udpsize == 512U)
add_triededns512(fctx, &query->addrinfo->sockaddr);
/*
@@ -2612,7 +2705,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
* Don't pound on remote servers. (Failsafe!)
*/
fctx->restarts++;
- if (fctx->restarts > 10) {
+ if (fctx->restarts > 100) {
FCTXTRACE("too many restarts");
return (DNS_R_SERVFAIL);
}
@@ -3142,6 +3235,7 @@ fctx_unlink(fetchctx_t *fctx) {
static void
fctx_destroy(fetchctx_t *fctx) {
isc_sockaddr_t *sa, *next_sa;
+ struct tried *tried;
REQUIRE(VALID_FCTX(fctx));
REQUIRE(fctx->state == fetchstate_done ||
@@ -3168,20 +3262,18 @@ fctx_destroy(fetchctx_t *fctx) {
isc_mem_put(fctx->mctx, sa, sizeof(*sa));
}
- for (sa = ISC_LIST_HEAD(fctx->edns);
- sa != NULL;
- sa = next_sa) {
- next_sa = ISC_LIST_NEXT(sa, link);
- ISC_LIST_UNLINK(fctx->edns, sa, link);
- isc_mem_put(fctx->mctx, sa, sizeof(*sa));
+ for (tried = ISC_LIST_HEAD(fctx->edns);
+ tried != NULL;
+ tried = ISC_LIST_HEAD(fctx->edns)) {
+ ISC_LIST_UNLINK(fctx->edns, tried, link);
+ isc_mem_put(fctx->mctx, tried, sizeof(*tried));
}
- for (sa = ISC_LIST_HEAD(fctx->edns512);
- sa != NULL;
- sa = next_sa) {
- next_sa = ISC_LIST_NEXT(sa, link);
- ISC_LIST_UNLINK(fctx->edns512, sa, link);
- isc_mem_put(fctx->mctx, sa, sizeof(*sa));
+ for (tried = ISC_LIST_HEAD(fctx->edns512);
+ tried != NULL;
+ tried = ISC_LIST_HEAD(fctx->edns512)) {
+ ISC_LIST_UNLINK(fctx->edns512, tried, link);
+ isc_mem_put(fctx->mctx, tried, sizeof(*tried));
}
for (sa = ISC_LIST_HEAD(fctx->bad_edns);
@@ -6907,6 +6999,13 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
goto done;
}
+ if ((options & DNS_FETCHOPT_TCP) == 0) {
+ if ((options & DNS_FETCHOPT_NOEDNS0) == 0)
+ dns_adb_setudpsize(fctx->adb, query->addrinfo,
+ isc_buffer_usedlength(&devent->buffer));
+ else
+ dns_adb_plainresponse(fctx->adb, query->addrinfo);
+ }
result = dns_message_parse(message, &devent->buffer, 0);
if (result != ISC_R_SUCCESS) {
switch (result) {
@@ -7019,12 +7118,66 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
message->rcode == dns_rcode_refused ||
message->rcode == dns_rcode_yxdomain) &&
bad_edns(fctx, &query->addrinfo->sockaddr)) {
- char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+/*
+ * XXXMPA We need to drop/remove the logging here when we have more
+ * experience.
+ */
+ char buf[4096], addrbuf[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
sizeof(addrbuf));
+ snprintf(buf, sizeof(buf), "received packet from %s "
+ "(bad edns):\n", addrbuf);
+ dns_message_logpacket(message, buf,
+ DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
+ ISC_LOG_NOTICE, fctx->res->mctx);
dns_adb_changeflags(fctx->adb, query->addrinfo,
DNS_FETCHOPT_NOEDNS0,
DNS_FETCHOPT_NOEDNS0);
+ } else if (opt == NULL && (message->flags & DNS_MESSAGEFLAG_TC) == 0 &&
+ (message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain) &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ /*
+ * Old versions of named incorrectly drop the OPT record
+ * when there is a signed, truncated response so check that
+ * TC is not set.
+ */
+/*
+ * XXXMPA We need to drop/remove the logging here when we have more
+ * experience.
+ */
+ char buf[4096], addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ /*
+ * We didn't get a OPT record in response to a EDNS query.
+ * Record that the server is not talking EDNS. While this
+ * should be safe to do for any rcode we limit it to NOERROR
+ * and NXDOMAIN.
+ */
+ isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
+ sizeof(addrbuf));
+ snprintf(buf, sizeof(buf), "received packet from %s (no opt):\n",
+ addrbuf);
+ dns_message_logpacket(message, buf,
+ DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
+ ISC_LOG_NOTICE, fctx->res->mctx);
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ }
+
+ /*
+ * If we get a non error response to a EDNS query record the fact
+ * so we won't fallback to plain DNS in the future for this server.
+ */
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ (query->addrinfo->flags & FCTX_ADDRINFO_EDNSOK) == 0 &&
+ (message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain ||
+ message->rcode == dns_rcode_refused ||
+ message->rcode == dns_rcode_yxdomain)) {
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ FCTX_ADDRINFO_EDNSOK,
+ FCTX_ADDRINFO_EDNSOK);
}
/*
@@ -7038,6 +7191,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
if ((options & DNS_FETCHOPT_TCP) != 0) {
broken_server = DNS_R_TRUNCATEDTCP;
keep_trying = ISC_TRUE;
+ } else if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ (query->options & DNS_FETCHOPT_EDNS512) == 0 &&
+ !triededns(fctx, &query->addrinfo->sockaddr)) {
+ resend = ISC_TRUE;
} else {
options |= DNS_FETCHOPT_TCP;
resend = ISC_TRUE;