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