xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/rrl/tests.sh (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
1#!/bin/sh
2
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# SPDX-License-Identifier: MPL-2.0
6#
7# This Source Code Form is subject to the terms of the Mozilla Public
8# License, v. 2.0.  If a copy of the MPL was not distributed with this
9# file, you can obtain one at https://mozilla.org/MPL/2.0/.
10#
11# See the COPYRIGHT file distributed with this work for additional
12# information regarding copyright ownership.
13
14set -e
15
16# test response rate limiting
17
18. ../conf.sh
19
20RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
21
22#set -x
23
24ns1=10.53.0.1 # root, defining the others
25ns2=10.53.0.2 # test server
26ns3=10.53.0.3 # secondary test server
27ns4=10.53.0.4 # log-only test server
28ns7=10.53.0.7 # whitelisted client
29
30USAGE="$0: [-x]"
31while getopts "x" c; do
32  case $c in
33    x) set -x ;;
34    *)
35      echo "$USAGE" 1>&2
36      exit 1
37      ;;
38  esac
39done
40shift $((OPTIND - 1))
41if test "$#" -ne 0; then
42  echo "$USAGE" 1>&2
43  exit 1
44fi
45# really quit on control-C
46trap 'exit 1' 1 2 15
47
48ret=0
49setret() {
50  ret=1
51  echo_i "$*"
52}
53
54# Wait until soon after the start of a second to make results consistent.
55#   The start of a second credits a rate limit.
56#   This would be far easier in C or by assuming a modern version of perl.
57sec_start() {
58  START=$(date)
59  while true; do
60    NOW=$(date)
61    if test "$START" != "$NOW"; then
62      return
63    fi
64    $PERL -e 'select(undef, undef, undef, 0.05)' || true
65  done
66}
67
68# turn off ${HOME}/.digrc
69HOME=/dev/null
70export HOME
71
72#   $1=number of tests  $2=target domain  $3=dig options
73QNUM=1
74burst() {
75  BURST_LIMIT=$1
76  shift
77  BURST_DOM_BASE="$1"
78  shift
79
80  XCNT=$CNT
81  CNT='XXX'
82  eval FILENAME="mdig.out-$BURST_DOM_BASE"
83  CNT=$XCNT
84
85  DOMS=""
86  CNTS=$($PERL -e 'for ( $i = 0; $i < '$BURST_LIMIT'; $i++) { printf "%03d\n", '$QNUM' + $i; }')
87  for CNT in $CNTS; do
88    eval BURST_DOM="$BURST_DOM_BASE"
89    DOMS="$DOMS $BURST_DOM"
90  done
91  ARGS="+burst +nocookie +continue +time=1 +tries=1 -p ${PORT} $* @$ns2 $DOMS"
92  $MDIG $ARGS 2>&1 \
93    | tee -a full-$FILENAME \
94    | sed -n -e '/^;; AUTHORITY/,/^$/d' \
95      -e '/^;; ADDITIONAL/,/^$/d' \
96      -e 's/^[^;].*	\([^	 ]\{1,\}\)$/\1/p' \
97      -e 's/;; flags.* tc .*/TC/p' \
98      -e 's/;; .* status: NXDOMAIN.*/NXDOMAIN/p' \
99      -e 's/;; .* status: NOERROR.*/NOERROR/p' \
100      -e 's/;; .* status: SERVFAIL.*/SERVFAIL/p' \
101      -e 's/response failed with timed out.*/drop/p' \
102      -e 's/;; communications error to.*/drop/p' >>$FILENAME &
103  QNUM=$((QNUM + BURST_LIMIT))
104}
105
106# compare integers $1 and $2; ensure the difference is no more than $3
107range() {
108  $PERL -e 'if (abs(int($ARGV[0]) - int($ARGV[1])) > int($ARGV[2])) { exit(1) }' $1 $2 $3
109}
110
111#   $1=domain  $2=IP address  $3=# of IP addresses  $4=TC  $5=drop
112#	$6=NXDOMAIN  $7=SERVFAIL or other errors
113ck_result() {
114  # wait to the background mdig calls to complete.
115  wait
116  BAD=no
117  ADDRS=$(grep -E "^$2$" mdig.out-$1 2>/dev/null | wc -l)
118  # count simple truncated and truncated NXDOMAIN as TC
119  TC=$(grep -E "^TC|NXDOMAINTC$" mdig.out-$1 2>/dev/null | wc -l)
120  DROP=$(grep -E "^drop$" mdig.out-$1 2>/dev/null | wc -l)
121  # count NXDOMAIN and truncated NXDOMAIN as NXDOMAIN
122  NXDOMAIN=$(grep -E "^NXDOMAIN|NXDOMAINTC$" mdig.out-$1 2>/dev/null | wc -l)
123  SERVFAIL=$(grep -E "^SERVFAIL$" mdig.out-$1 2>/dev/null | wc -l)
124  NOERROR=$(grep -E "^NOERROR$" mdig.out-$1 2>/dev/null | wc -l)
125
126  range $ADDRS "$3" 1 \
127    || setret "$ADDRS instead of $3 '$2' responses for $1" \
128    && BAD=yes
129
130  range $TC "$4" 1 \
131    || setret "$TC instead of $4 truncation responses for $1" \
132    && BAD=yes
133
134  range $DROP "$5" 1 \
135    || setret "$DROP instead of $5 dropped responses for $1" \
136    && BAD=yes
137
138  range $NXDOMAIN "$6" 1 \
139    || setret "$NXDOMAIN instead of $6 NXDOMAIN responses for $1" \
140    && BAD=yes
141
142  range $SERVFAIL "$7" 1 \
143    || setret "$SERVFAIL instead of $7 error responses for $1" \
144    && BAD=yes
145
146  range $NOERROR "$8" 1 \
147    || setret "$NOERROR instead of $8 NOERROR responses for $1" \
148    && BAD=yes
149
150  if test -z "$BAD"; then
151    rm -f mdig.out-$1
152  fi
153}
154
155ckstats() {
156  LABEL="$1"
157  shift
158  TYPE="$1"
159  shift
160  EXPECTED="$1"
161  shift
162  C=$(cat ns2/named.stats \
163    | sed -n -e "s/[	 ]*\([0-9]*\).responses $TYPE for rate limits.*/\1/p" \
164    | tail -1)
165  C=$((C))
166
167  range "$C" $EXPECTED 1 \
168    || setret "wrong $LABEL $TYPE statistics of $C instead of $EXPECTED"
169}
170
171#########
172sec_start
173
174# Tests of referrals to "." must be done before the hints are loaded.
175burst 5 a1.tld3 +norec
176# basic rate limiting
177burst 3 a1.tld2
178# delay allows an additional response.
179sleep 1
180burst 10 a1.tld2
181# Request 30 different qnames to try a wildcard.
182burst 30 'y.x$CNT.a2.tld2'
183
184#					IP      TC      drop  NXDOMAIN SERVFAIL NOERROR
185# referrals to "."
186ck_result a1.tld3 x 0 1 2 0 0 2
187# check 13 results including 1 second delay that allows an additional response
188ck_result a1.tld2 192.0.2.1 3 4 6 0 0 8
189
190# Check the wildcard answers.
191# The zone origin name of the 30 requests is counted.
192ck_result 'y.x*.a2.tld2' 192.0.2.2 2 10 18 0 0 12
193
194#########
195sec_start
196
197burst 10 'x.a3.tld3'
198burst 10 'y$CNT.a3.tld3'
199burst 10 'z$CNT.a4.tld2'
200
201# 10 identical recursive responses are limited
202ck_result 'x.a3.tld3' 192.0.3.3 2 3 5 0 0 5
203
204# 10 different recursive responses are not limited
205ck_result 'y*.a3.tld3' 192.0.3.3 10 0 0 0 0 10
206
207# 10 different NXDOMAIN responses are limited based on the parent name.
208#   We count 13 responses because we count truncated NXDOMAIN responses
209#   as both truncated and NXDOMAIN.
210ck_result 'z*.a4.tld2' x 0 3 5 5 0 0
211
212$RNDCCMD $ns2 stats
213ckstats first dropped 36
214ckstats first truncated 21
215
216#########
217sec_start
218
219burst 10 a5.tld2 +tcp
220burst 10 a6.tld2 -b $ns7
221burst 10 a7.tld4
222burst 2 a8.tld2 -t AAAA
223burst 2 a8.tld2 -t TXT
224burst 2 a8.tld2 -t SPF
225
226#					IP      TC      drop  NXDOMAIN SERVFAIL NOERROR
227# TCP responses are not rate limited
228ck_result a5.tld2 192.0.2.5 10 0 0 0 0 10
229
230# whitelisted client is not rate limited
231ck_result a6.tld2 192.0.2.6 10 0 0 0 0 10
232
233# Errors such as SERVFAIL are rate limited.
234ck_result a7.tld4 x 0 0 8 0 2 0
235
236# NODATA responses are counted as the same regardless of qtype.
237ck_result a8.tld2 x 0 2 2 0 0 4
238
239$RNDCCMD $ns2 stats
240ckstats second dropped 46
241ckstats second truncated 23
242
243#########
244sec_start
245
246#					IP      TC      drop  NXDOMAIN SERVFAIL NOERROR
247# all-per-second
248#   The qnames are all unique but the client IP address is constant.
249QNUM=101
250burst 60 'all$CNT.a9.tld2'
251
252ck_result 'a*.a9.tld2' 192.0.2.8 50 0 10 0 0 50
253
254$RNDCCMD $ns2 stats
255ckstats final dropped 56
256ckstats final truncated 23
257
258#########
259sec_start
260
261DIGOPTS="+nocookie +nosearch +time=1 +tries=1 +ignore -p ${PORT}"
262$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
263$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
264$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
265$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
266$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
267$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
268$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
269$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
270$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
271$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
272$DIG $DIGOPTS @$ns4 A a7.tld4 >/dev/null 2>&1
273
274# regression test for GL #2839
275DIGOPTS="+bufsize=4096 +ignore -p ${PORT}"
276$DIG $DIGOPTS @$ns4 TXT big.tld4 >/dev/null 2>&1
277
278grep "would limit" ns4/named.run >/dev/null 2>&1 \
279  || setret "\"would limit\" not found in log file."
280
281echo_i "exit status: $ret"
282[ $ret -eq 0 ] || exit 1
283