1# Copyright (C) 2012, 2013  Internet Systems Consortium, Inc. ("ISC")
2#
3# Permission to use, copy, modify, and/or distribute this software for any
4# purpose with or without fee is hereby granted, provided that the above
5# copyright notice and this permission notice appear in all copies.
6#
7# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13# PERFORMANCE OF THIS SOFTWARE.
14
15
16# test response rate limiting
17
18SYSTEMTESTTOP=..
19. $SYSTEMTESTTOP/conf.sh
20
21#set -x
22
23ns1=10.53.0.1			    # root, defining the others
24ns2=10.53.0.2			    # test server
25ns3=10.53.0.3			    # secondary test server
26ns7=10.53.0.7			    # whitelisted client
27
28USAGE="$0: [-x]"
29while getopts "x" c; do
30    case $c in
31	x) set -x;;
32	*) echo "$USAGE" 1>&2; exit 1;;
33    esac
34done
35shift `expr $OPTIND - 1 || true`
36if test "$#" -ne 0; then
37    echo "$USAGE" 1>&2
38    exit 1
39fi
40# really quit on control-C
41trap 'exit 1' 1 2 15
42
43
44ret=0
45setret () {
46    ret=1
47    echo "$*"
48}
49
50
51# Wait until soon after the start of a second to make results consistent.
52#   The start of a second credits a rate limit.
53#   This would be far easier in C or by assuming a modern version of perl.
54sec_start () {
55    START=`date`
56    while true; do
57	NOW=`date`
58	if test "$START" != "$NOW"; then
59	    return
60	fi
61	$PERL -e 'select(undef, undef, undef, 0.05)' || true
62    done
63}
64
65
66# turn off ${HOME}/.digrc
67HOME=/dev/null; export HOME
68
69#   $1=result name  $2=domain name  $3=dig options
70digcmd () {
71    OFILE=$1; shift
72    DIG_DOM=$1; shift
73    ARGS="+nosearch +time=1 +tries=1 +ignore -p 5300 $* $DIG_DOM @$ns2"
74    #echo I:dig $ARGS 1>&2
75    START=`date +%y%m%d%H%M.%S`
76    RESULT=`$DIG $ARGS 2>&1 | tee $OFILE=TEMP				\
77	    | sed -n -e '/^;; AUTHORITY/,/^$/d'				\
78		-e '/^;; ADDITIONAL/,/^$/d'				\
79		-e  's/^[^;].*	\([^	 ]\{1,\}\)$/\1/p'		\
80		-e 's/;; flags.* tc .*/TC/p'				\
81		-e 's/;; .* status: NXDOMAIN.*/NXDOMAIN/p'		\
82		-e 's/;; .* status: SERVFAIL.*/SERVFAIL/p'		\
83		-e 's/;; connection timed out.*/drop/p'			\
84		-e 's/;; communications error to.*/drop/p'		\
85	    | tr -d '\n'`
86    mv "$OFILE=TEMP" "$OFILE=$RESULT"
87    touch -t $START "$OFILE=$RESULT"
88}
89
90
91#   $1=number of tests  $2=target domain  $3=dig options
92QNUM=1
93burst () {
94    BURST_LIMIT=$1; shift
95    BURST_DOM_BASE="$1"; shift
96    while test "$BURST_LIMIT" -ge 1; do
97	CNT=`expr "00$QNUM" : '.*\(...\)'`
98	eval BURST_DOM="$BURST_DOM_BASE"
99	FILE="dig.out-$BURST_DOM-$CNT"
100	digcmd $FILE $BURST_DOM $* &
101	QNUM=`expr $QNUM + 1`
102	BURST_LIMIT=`expr "$BURST_LIMIT" - 1`
103    done
104}
105
106
107#   $1=domain  $2=IP address  $3=# of IP addresses  $4=TC  $5=drop
108#	$6=NXDOMAIN  $7=SERVFAIL or other errors
109ck_result() {
110    BAD=
111    wait
112    ADDRS=`ls dig.out-$1-*=$2				2>/dev/null | wc -l`
113    # count simple truncated and truncated NXDOMAIN as TC
114    TC=`ls dig.out-$1-*=TC dig.out-$1-*=NXDOMAINTC	2>/dev/null | wc -l`
115    DROP=`ls dig.out-$1-*=drop				2>/dev/null | wc -l`
116    # count NXDOMAIN and truncated NXDOMAIN as NXDOMAIN
117    NXDOMAIN=`ls dig.out-$1-*=NXDOMAIN  dig.out-$1-*=NXDOMAINTC	2>/dev/null \
118							| wc -l`
119    SERVFAIL=`ls dig.out-$1-*=SERVFAIL			2>/dev/null | wc -l`
120    if test $ADDRS -ne "$3"; then
121	setret "I:"$ADDRS" instead of $3 '$2' responses for $1"
122	BAD=yes
123    fi
124    if test $TC -ne "$4"; then
125	setret "I:"$TC" instead of $4 truncation responses for $1"
126	BAD=yes
127    fi
128    if test $DROP -ne "$5"; then
129	setret "I:"$DROP" instead of $5 dropped responses for $1"
130	BAD=yes
131    fi
132    if test $NXDOMAIN -ne "$6"; then
133	setret "I:"$NXDOMAIN" instead of $6 NXDOMAIN responses for $1"
134	BAD=yes
135    fi
136    if test $SERVFAIL -ne "$7"; then
137	setret "I:"$SERVFAIL" instead of $7 error responses for $1"
138	BAD=yes
139    fi
140    if test -z "$BAD"; then
141	rm -f dig.out-$1-*
142    fi
143}
144
145
146ckstats () {
147    LABEL="$1"; shift
148    TYPE="$1"; shift
149    EXPECTED="$1"; shift
150    C=`sed -n -e "s/[	 ]*\([0-9]*\).responses $TYPE for rate limits.*/\1/p"  \
151	    ns2/named.stats | tail -1`
152    C=`expr 0$C + 0`
153    if test "$C" -ne $EXPECTED; then
154	setret "I:wrong $LABEL $TYPE statistics of $C instead of $EXPECTED"
155    fi
156}
157
158
159#########
160sec_start
161
162# Tests of referrals to "." must be done before the hints are loaded
163#   or with "additional-from-cache no"
164burst 5 a1.tld3 +norec
165# basic rate limiting
166burst 3 a1.tld2
167# 1 second delay allows an additional response.
168sleep 1
169burst 10 a1.tld2
170# Request 30 different qnames to try a wildcard.
171burst 30 'x$CNT.a2.tld2'
172# These should be counted and limited but are not.  See RT33138.
173burst 10 'y.x$CNT.a2.tld2'
174
175#					IP      TC      drop  NXDOMAIN SERVFAIL
176# referrals to "."
177ck_result   a1.tld3	''		2	1	2	0	0
178# check 13 results including 1 second delay that allows an additional response
179ck_result   a1.tld2	192.0.2.1	3	4	6	0	0
180
181# Check the wild card answers.
182# The parent name of the 30 requests is counted.
183ck_result 'x*.a2.tld2'	192.0.2.2	2	10	18	0	0
184
185# These should be limited but are not.  See RT33138.
186ck_result 'y.x*.a2.tld2' 192.0.2.2	10	0	0	0	0
187
188#########
189sec_start
190
191burst 10 'x.a3.tld3'
192burst 10 'y$CNT.a3.tld3'
193burst 10 'z$CNT.a4.tld2'
194
195# 10 identical recursive responses are limited
196ck_result 'x.a3.tld3'	192.0.3.3	2	3	5	0	0
197
198# 10 different recursive responses are not limited
199ck_result 'y*.a3.tld3'	192.0.3.3	10	0	0	0	0
200
201# 10 different NXDOMAIN responses are limited based on the parent name.
202#   We count 13 responses because we count truncated NXDOMAIN responses
203#   as both truncated and NXDOMAIN.
204ck_result 'z*.a4.tld2'	x		0	3	5	5	0
205
206$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
207ckstats first dropped 36
208ckstats first truncated 21
209
210
211#########
212sec_start
213
214burst 10 a5.tld2 +tcp
215burst 10 a6.tld2 -b $ns7
216burst 10 a7.tld4
217burst 2 a8.tld2 AAAA
218burst 2 a8.tld2 TXT
219burst 2 a8.tld2 SPF
220
221#					IP      TC      drop  NXDOMAIN SERVFAIL
222# TCP responses are not rate limited
223ck_result a5.tld2	192.0.2.5	10	0	0	0	0
224
225# whitelisted client is not rate limited
226ck_result a6.tld2	192.0.2.6	10	0	0	0	0
227
228# Errors such as SERVFAIL are rate limited.
229ck_result a7.tld4	x		0	0	8	0	2
230
231# NODATA responses are counted as the same regardless of qtype.
232ck_result a8.tld2	''		2	2	2	0	0
233
234$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
235ckstats second dropped 46
236ckstats second truncated 23
237
238
239#########
240sec_start
241
242#					IP      TC      drop  NXDOMAIN SERVFAIL
243# all-per-second
244#   The qnames are all unique but the client IP address is constant.
245QNUM=101
246burst 60 'all$CNT.a9.tld2'
247
248ck_result 'a*.a9.tld2'	192.0.2.8	50	0	10	0	0
249
250$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
251ckstats final dropped 56
252ckstats final truncated 23
253
254
255echo "I:exit status: $ret"
256# exit $ret
257[ $ret -ne 0 ] && echo "I:test failure overridden"
258exit 0
259