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