2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

3593. [func] Update EDNS processing to better track remote server

capabilities. [RT #30655]
This commit is contained in:
Mark Andrews 2013-06-12 11:31:30 +10:00
parent 0ccb0e98c7
commit 8e15d5eb3a
23 changed files with 1059 additions and 154 deletions

View File

@ -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]

31
EDNS-9.10 Normal file
View File

@ -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.

View File

@ -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;

View File

@ -62,6 +62,7 @@
<arg><option>-6</option></arg>
<arg><option>-c <replaceable class="parameter">config-file</replaceable></option></arg>
<arg><option>-d <replaceable class="parameter">debug-level</replaceable></option></arg>
<arg><option>-D <replaceable class="parameter">string</replaceable></option></arg>
<arg><option>-E <replaceable class="parameter">engine-name</replaceable></option></arg>
<arg><option>-f</option></arg>
<arg><option>-g</option></arg>
@ -149,6 +150,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-D <replaceable class="parameter">string</replaceable></term>
<listitem>
<para>
Specifies a string that is used to identify a instance of
<command>named</command> in a process listing. The contents
of <replaceable class="parameter">string</replaceable> are
not examined.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-E <replaceable class="parameter">engine-name</replaceable></term>
<listitem>

15
bin/tests/bigtest/README Normal file
View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
key "rndc-key" {
algorithm hmac-md5;
secret "xxxxxxxxxxxxxxxxxxxxHg==";
};

View File

@ -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

18
bin/tests/bigtest/zones Normal file
View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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`

View File

@ -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`

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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"; }

View File

@ -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)

View File

@ -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);

View File

@ -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;