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