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