xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/rpz/tests.sh (revision 33881f779a77dce6440bdc44610d94de75bebefe)
1#!/bin/sh
2#
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
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 http://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 policy zones (RPZ)
13
14# touch dnsrps-off to not test with DNSRPS
15# touch dnsrps-only to not test with classic RPZ
16
17SYSTEMTESTTOP=..
18. $SYSTEMTESTTOP/conf.sh
19
20ns=10.53.0
21ns1=$ns.1		# root, defining the others
22ns2=$ns.2		# authoritative server whose records are rewritten
23ns3=$ns.3		# main rewriting resolver
24ns4=$ns.4		# another authoritative server that is rewritten
25ns5=$ns.5		# another rewriting resolver
26ns6=$ns.6		# a forwarding server
27ns7=$ns.7		# another rewriting resolver
28ns8=$ns.8		# another rewriting resolver
29
30HAVE_CORE=
31
32status=0
33t=0
34
35DEBUG=
36SAVE_RESULTS=
37ARGS=
38
39USAGE="$0: [-xS]"
40while getopts "xS:" c; do
41    case $c in
42	x) set -x; DEBUG=-x; ARGS="$ARGS -x";;
43	S) SAVE_RESULTS=-S; ARGS="$ARGS -S";;
44	*) echo "$USAGE" 1>&2; exit 1;;
45    esac
46done
47shift `expr $OPTIND - 1 || true`
48if test "$#" -ne 0; then
49    echo "$USAGE" 1>&2
50    exit 1
51fi
52# really quit on control-C
53trap 'exit 1' 1 2 15
54
55TS='%H:%M:%S '
56TS=
57comment () {
58    if test -n "$TS"; then
59	date "+${TS}$*" | cat_i
60    fi
61}
62
63DNSRPSCMD=./dnsrps
64RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
65
66if test -x $DNSRPSCMD; then
67    # speed up the many delays for dnsrpzd by waiting only 0.1 seconds
68    WAIT_CMD="$DNSRPSCMD -w 0.1"
69    TEN_SECS=100
70else
71    WAIT_CMD="sleep 1"
72    TEN_SECS=10
73fi
74
75digcmd () {
76    if test "$1" = TCP; then
77	shift
78    fi
79    # Default to +noauth and @$ns3
80    # Also default to -bX where X is the @value so that OS X will choose
81    #	    the right IP source address.
82    digcmd_args=`echo "+nocookie +noadd +time=2 +tries=1 -p ${PORT} $*" |	\
83	    sed -e "/@/!s/.*/& @$ns3/"					\
84		-e '/-b/!s/@\([^ ]*\)/@\1 -b\1/'			\
85		-e '/+n?o?auth/!s/.*/+noauth &/'`
86    #echo_i "dig $digcmd_args 1>&2
87    $DIG $digcmd_args
88}
89
90# set DIGNM=file name for dig output
91GROUP_NM=
92TEST_NUM=0
93make_dignm () {
94    TEST_NUM=`expr $TEST_NUM : '\([0-9]*\).*'`	    # trim '+' characters
95    TEST_NUM=`expr $TEST_NUM + 1`
96    DIGNM=dig.out$GROUP_NM-$TEST_NUM
97    while test -f $DIGNM; do
98	TEST_NUM="$TEST_NUM+"
99	DIGNM=dig.out$GROUP_NM-$TEST_NUM
100    done
101}
102
103setret () {
104    ret=1
105    status=`expr $status + 1`
106    echo_i "$*"
107}
108
109# set $SN to the SOA serial number of a zone
110# $1=domain
111# $2=DNS server and client IP address
112get_sn() {
113    SOA=`$DIG -p ${PORT} +short +norecurse soa "$1" "@$2" "-b$2"`
114    SN=`expr "$SOA" : '[^ ]* [^ ]* \([^ ]*\) .*'`
115    test "$SN" != "" && return
116    echo_i "no serial number from \`dig -p ${PORT} soa $1 @$2\` in \"$SOA\""
117    exit 1
118}
119
120get_sn_fast () {
121    RSN=`$DNSRPSCMD -n "$1"`
122    #echo "dnsrps serial for $1 is $RSN"
123    if test -z "$RSN"; then
124	echo_i "dnsrps failed to get SOA serial number for $1"
125	exit 1
126    fi
127}
128
129# check that dnsrpzd has loaded its zones
130# $1=domain
131# $2=DNS server IP address
132FZONES=`sed -n -e 's/^zone "\(.*\)".*\(10.53.0..\).*/Z=\1;M=\2/p' dnsrpzd.conf`
133dnsrps_loaded() {
134    test "$mode" = dnsrps || return
135    n=0
136    for V in $FZONES; do
137	eval "$V"
138	get_sn $Z $M
139	while true; do
140	    get_sn_fast "$Z"
141	    if test "$SN" -eq "0$RSN"; then
142		#echo "$Z @$M serial=$SN"
143		break
144	    fi
145	    n=`expr $n + 1`
146	    if test "$n" -gt $TEN_SECS; then
147		echo_i "dnsrps serial for $Z is $RSN instead of $SN"
148		exit 1
149	    fi
150	    $WAIT_CMD
151	done
152    done
153}
154
155# check the serial number in an SOA to ensure that a policy zone has
156#   been (re)loaded
157# $1=serial number
158# $2=domain
159# $3=DNS server
160ck_soa() {
161    n=0
162    while true; do
163	if test "$mode" = dnsrps; then
164	    get_sn_fast "$2"
165	    test "$RSN" -eq "$1" && return
166	else
167	    get_sn "$2" "$3"
168	    test "$SN" -eq "$1" && return
169	fi
170	n=`expr $n + 1`
171	if test "$n" -gt $TEN_SECS; then
172	    echo_i "got serial number \"$SN\" instead of \"$1\" from $2 @$3"
173	    return
174	fi
175	$WAIT_CMD
176    done
177}
178
179# (re)load the reponse policy zones with the rules in the file $TEST_FILE
180load_db () {
181    if test -n "$TEST_FILE"; then
182        copy_setports $TEST_FILE tmp
183	if $NSUPDATE -v tmp; then :
184	    $RNDCCMD $ns3 sync
185	else
186	    echo_i "failed to update policy zone with $TEST_FILE"
187	    $RNDCCMD $ns3 sync
188	    exit 1
189	fi
190        rm -f tmp
191    fi
192}
193
194# restart name server
195# $1 ns number
196# $2 rebuild bl rpz zones if "rebuild-bl-rpz"
197restart () {
198    # try to ensure that the server really has stopped
199    # and won't mess with ns$1/name.pid
200    if test -z "$HAVE_CORE" -a -f ns$1/named.pid; then
201	$RNDCCMD $ns$1 halt >/dev/null 2>&1
202	if test -f ns$1/named.pid; then
203	    sleep 1
204	    PID=`cat ns$1/named.pid 2>/dev/null`
205	    if test -n "$PID"; then
206		echo_i "killing ns$1 server $PID"
207		$KILL -9 $PID
208	    fi
209	fi
210    fi
211    rm -f ns$1/*.jnl
212    if [ "$2" == "rebuild-bl-rpz" ]; then
213        if test -f ns$1/base.db; then
214	    for NM in ns$1/bl*.db; do
215	        cp -f ns$1/base.db $NM
216            done
217        fi
218    fi
219    $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} rpz ns$1
220    load_db
221    dnsrps_loaded
222}
223
224# $1=server and irrelevant args
225# $2=error message
226ckalive () {
227    CKALIVE_NS=`expr "$1" : '.*@ns\([1-9]\).*'`
228    if test -z "$CKALIVE_NS"; then
229	CKALIVE_NS=3
230    fi
231    eval CKALIVE_IP=\$ns$CKALIVE_NS
232    $RNDCCMD $CKALIVE_IP status >/dev/null 2>&1 && return 0
233    HAVE_CORE=yes
234    setret "$2"
235    # restart the server to avoid stalling waiting for it to stop
236    restart $CKALIVE_NS "rebuild-bl-rpz"
237    return 1
238}
239
240resetstats () {
241        NSDIR=$1
242        eval "${NSDIR}_CNT=''"
243}
244
245ckstats () {
246    HOST=$1
247    LABEL="$2"
248    NSDIR="$3"
249    EXPECTED="$4"
250    $RNDCCMD $HOST stats
251    NEW_CNT=0`sed -n -e 's/[	 ]*\([0-9]*\).response policy.*/\1/p'  \
252		    $NSDIR/named.stats | tail -1`
253    eval "OLD_CNT=0\$${NSDIR}_CNT"
254    GOT=`expr $NEW_CNT - $OLD_CNT`
255    if test "$GOT" -ne "$EXPECTED"; then
256	setret "wrong $LABEL $NSDIR statistics of $GOT instead of $EXPECTED"
257    fi
258    eval "${NSDIR}_CNT=$NEW_CNT"
259}
260
261ckstatsrange () {
262    HOST=$1
263    LABEL="$2"
264    NSDIR="$3"
265    MIN="$4"
266    MAX="$5"
267    $RNDCCMD $HOST stats
268    NEW_CNT=0`sed -n -e 's/[	 ]*\([0-9]*\).response policy.*/\1/p'  \
269		    $NSDIR/named.stats | tail -1`
270    eval "OLD_CNT=0\$${NSDIR}_CNT"
271    GOT=`expr $NEW_CNT - $OLD_CNT`
272    if test "$GOT" -lt "$MIN" -o "$GOT" -gt "$MAX"; then
273	setret "wrong $LABEL $NSDIR statistics of $GOT instead of ${MIN}..${MAX}"
274    fi
275    eval "${NSDIR}_CNT=$NEW_CNT"
276}
277
278# $1=message
279# $2=optional test file name
280start_group () {
281    ret=0
282    t=`expr $t + 1`
283    test -n "$1" && date "+${TS}checking $1 (${t})" | cat_i
284    TEST_FILE=$2
285    if test -n "$TEST_FILE"; then
286	GROUP_NM="-$TEST_FILE"
287	load_db
288    else
289	GROUP_NM=
290    fi
291    dnsrps_loaded
292    TEST_NUM=0
293}
294
295end_group () {
296    if test -n "$TEST_FILE"; then
297	# remove the previous set of test rules
298        copy_setports $TEST_FILE tmp
299	sed -e 's/[	 ]add[	 ]/ delete /' tmp | $NSUPDATE
300        rm -f tmp
301	TEST_FILE=
302    fi
303    ckalive $ns3 "failed; ns3 server crashed and restarted"
304    dnsrps_loaded
305    GROUP_NM=
306}
307
308clean_result () {
309    if test -z "$SAVE_RESULTS"; then
310	rm -f $*
311    fi
312}
313
314# $1=dig args
315# $2=other dig output file
316ckresult () {
317    #ckalive "$1" "server crashed by 'dig $1'" || return 1
318    if grep "flags:.* aa .*ad;" $DIGNM; then
319	setret "'dig $1' AA and AD set;"
320    elif grep "flags:.* aa .*ad;" $DIGNM; then
321	setret "'dig $1' AD set;"
322    fi
323    if $PERL $SYSTEMTESTTOP/digcomp.pl $DIGNM $2 >/dev/null; then
324	NEED_TCP=`echo "$1" | sed -n -e 's/[Tt][Cc][Pp].*/TCP/p'`
325	RESULT_TCP=`sed -n -e 's/.*Truncated, retrying in TCP.*/TCP/p' $DIGNM`
326	if test "$NEED_TCP" != "$RESULT_TCP"; then
327	    setret "'dig $1' wrong; no or unexpected truncation in $DIGNM"
328	    return 1
329	fi
330	clean_result ${DIGNM}*
331	return 0
332    fi
333    setret "'dig $1' wrong; diff $DIGNM $2"
334    return 1
335}
336
337# check only that the server does not crash
338# $1=target domain
339# $2=optional query type
340nocrash () {
341    digcmd $* >/dev/null
342    ckalive "$*" "server crashed by 'dig $*'"
343}
344
345
346# check rewrite to NXDOMAIN
347# $1=target domain
348# $2=optional query type
349nxdomain () {
350    make_dignm
351    digcmd $*								\
352	| sed -e 's/^[a-z].*	IN	CNAME	/;xxx &/'		\
353		-e 's/^[a-z].*	IN	RRSIG	/;xxx &/'		\
354	    >$DIGNM
355    ckresult "$*" proto.nxdomain
356}
357
358# check rewrite to NODATA
359# $1=target domain
360# $2=optional query type
361nodata () {
362    make_dignm
363    digcmd $*								\
364	| sed -e 's/^[a-z].*	IN	CNAME	/;xxx &/' >$DIGNM
365    ckresult "$*" proto.nodata
366}
367
368# check rewrite to an address
369#   modify the output so that it is easily compared, but save the original line
370# $1=IPv4 address
371# $2=digcmd args
372# $3=optional TTL
373addr () {
374    ADDR=$1
375    make_dignm
376    digcmd $2 >$DIGNM
377    #ckalive "$2" "server crashed by 'dig $2'" || return 1
378    ADDR_ESC=`echo "$ADDR" | sed -e 's/\./\\\\./g'`
379    ADDR_TTL=`tr -d '\r' < $DIGNM | sed -n -e "s/^[-.a-z0-9]\{1,\}[	 ]*\([0-9]*\)	IN	AA*	${ADDR_ESC}\$/\1/p"`
380    if test -z "$ADDR_TTL"; then
381	setret "'dig $2' wrong; no address $ADDR record in $DIGNM"
382	return 1
383    fi
384    if test -n "$3" && test "$ADDR_TTL" -ne "$3"; then
385	setret "'dig $2' wrong; TTL=$ADDR_TTL instead of $3 in $DIGNM"
386	return 1
387    fi
388    clean_result ${DIGNM}*
389}
390
391# Check that a response is not rewritten
392#   Use $ns1 instead of the authority for most test domains, $ns2 to prevent
393#   spurious differences for `dig +norecurse`
394# $1=optional "TCP"
395# remaining args for dig
396nochange () {
397    make_dignm
398    digcmd $* >$DIGNM
399    digcmd $* @$ns1 >${DIGNM}_OK
400    ckresult "$*" ${DIGNM}_OK && clean_result ${DIGNM}_OK
401}
402
403# check against a 'here document'
404here () {
405    make_dignm
406    sed -e 's/^[	 ]*//' >${DIGNM}_OK
407    digcmd $* >$DIGNM
408    ckresult "$*" ${DIGNM}_OK
409}
410
411# check dropped response
412DROPPED='^;; connection timed out; no servers could be reached'
413drop () {
414    make_dignm
415    digcmd $* >$DIGNM
416    if grep "$DROPPED" $DIGNM >/dev/null; then
417	clean_result ${DIGNM}*
418	return 0
419    fi
420    setret "'dig $1' wrong; response in $DIGNM"
421    return 1
422}
423
424nsd() {
425  $NSUPDATE -p ${PORT} << EOF
426  server $1
427  ttl 300
428  update $2 $3 IN CNAME .
429  update $2 $4 IN CNAME .
430  send
431EOF
432  sleep 2
433}
434
435for mode in native dnsrps; do
436  status=0
437  case ${mode} in
438  native)
439    if [ -e dnsrps-only ] ; then
440      echo_i "'dnsrps-only' found: skipping native RPZ sub-test"
441      continue
442    else
443      echo_i "running native RPZ sub-test"
444    fi
445    ;;
446  dnsrps)
447    if [ -e dnsrps-off ] ; then
448      echo_i "'dnsrps-off' found: skipping DNSRPS sub-test"
449      continue
450    fi
451    echo_i "attempting to configure servers with DNSRPS..."
452    $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz
453    $SHELL ./setup.sh -N -D $DEBUG
454    for server in ns*; do
455      resetstats $server
456    done
457    sed -n 's/^## //p' dnsrps.conf | cat_i
458    if grep '^#fail' dnsrps.conf >/dev/null; then
459      echo_i "exit status: 1"
460      exit 1
461    fi
462    if grep '^#skip' dnsrps.conf > /dev/null; then
463      echo_i "DNSRPS sub-test skipped"
464      continue
465    else
466      echo_i "running DNSRPS sub-test"
467      $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} rpz
468    fi
469    ;;
470  esac
471
472  # make prototype files to check against rewritten results
473  digcmd nonexistent @$ns2 >proto.nxdomain
474  digcmd txt-only.tld2 @$ns2 >proto.nodata
475
476  start_group "QNAME rewrites" test1
477  nochange .					# 1 do not crash or rewrite root
478  nxdomain a0-1.tld2				# 2
479  nodata a3-1.tld2				# 3
480  nodata a3-2.tld2				# 4 nodata at DNAME itself
481  nochange sub.a3-2.tld2			# 5 miss where DNAME might work
482  nxdomain a4-2.tld2				# 6 rewrite based on CNAME target
483  nxdomain a4-2-cname.tld2			# 7
484  nodata a4-3-cname.tld2			# 8
485  addr 12.12.12.12  a4-1.sub1.tld2		# 9 A replacement
486  addr 12.12.12.12  a4-1.sub2.tld2		# 10 A replacement with wildcard
487  addr 12.12.12.12  nxc1.sub1.tld2		# 11 replace NXDOMAIN with CNAME
488  addr 12.12.12.12  nxc2.sub1.tld2		# 12 replace NXDOMAIN with CNAME chain
489  addr 127.4.4.1    a4-4.tld2			# 13 prefer 1st conflicting QNAME zone
490  nochange a6-1.tld2				# 14
491  addr 127.6.2.1    a6-2.tld2			# 15
492  addr 56.56.56.56  a3-6.tld2			# 16 wildcard CNAME
493  addr 57.57.57.57  a3-7.sub1.tld2		# 17 wildcard CNAME
494  addr 127.0.0.16   a4-5-cname3.tld2		# 18 CNAME chain
495  addr 127.0.0.17   a4-6-cname3.tld2		# 19 stop short in CNAME chain
496  nochange a5-2.tld2 +norecurse			# 20 check that RD=1 is required
497  nochange a5-3.tld2 +norecurse			# 21
498  nochange a5-4.tld2 +norecurse			# 22
499  nochange sub.a5-4.tld2 +norecurse		# 23
500  nxdomain c1.crash2.tld3			# 24 assert in rbtdb.c
501  nxdomain a0-1.tld2  +dnssec			# 25 simple DO=1 without signatures
502  nxdomain a0-1.tld2s +nodnssec			# 26 simple DO=0 with signatures
503  nochange a0-1.tld2s +dnssec			# 27 simple DO=1 with signatures
504  nxdomain a0-1s-cname.tld2s +dnssec		# 28 DNSSEC too early in CNAME chain
505  nochange a0-1-scname.tld2  +dnssec		# 29 DNSSEC on target in CNAME chain
506  nochange a0-1.tld2s srv +auth +dnssec		# 30 no write for DNSSEC and no record
507  nxdomain a0-1.tld2s srv +nodnssec		# 31
508  drop a3-8.tld2 any				# 32 drop
509  nochange tcp a3-9.tld2			# 33 tcp-only
510  here x.servfail <<'EOF'			# 34 qname-wait-recurse yes
511    ;; status: SERVFAIL, x
512EOF
513  addr 35.35.35.35 "x.servfail @$ns5"		# 35 qname-wait-recurse no
514  end_group
515  ckstats $ns3 test1 ns3 22
516  ckstats $ns5 test1 ns5 1
517  ckstats $ns6 test1 ns6 0
518
519  start_group "NXDOMAIN/NODATA action on QNAME trigger" test1
520  nxdomain a0-1.tld2 @$ns6			# 1
521  nodata a3-1.tld2 @$ns6			# 2
522  nodata a3-2.tld2 @$ns6			# 3 nodata at DNAME itself
523  nxdomain a4-2.tld2 @$ns6			# 4 rewrite based on CNAME target
524  nxdomain a4-2-cname.tld2 @$ns6		# 5
525  nodata a4-3-cname.tld2 @$ns6			# 6
526  addr 12.12.12.12  "a4-1.sub1.tld2 @$ns6"	# 7 A replacement
527  addr 12.12.12.12  "a4-1.sub2.tld2 @$ns6"	# 8 A replacement with wildcard
528  addr 127.4.4.1    "a4-4.tld2 @$ns6"		# 9 prefer 1st conflicting QNAME zone
529  addr 12.12.12.12  "nxc1.sub1.tld2 @$ns6"	# 10 replace NXDOMAIN w/ CNAME
530  addr 12.12.12.12  "nxc2.sub1.tld2 @$ns6"	# 11 replace NXDOMAIN w/ CNAME chain
531  addr 127.6.2.1    "a6-2.tld2 @$ns6"		# 12
532  addr 56.56.56.56  "a3-6.tld2 @$ns6"		# 13 wildcard CNAME
533  addr 57.57.57.57  "a3-7.sub1.tld2 @$ns6"	# 14 wildcard CNAME
534  addr 127.0.0.16   "a4-5-cname3.tld2 @$ns6"	# 15 CNAME chain
535  addr 127.0.0.17   "a4-6-cname3.tld2 @$ns6"	# 16 stop short in CNAME chain
536  nxdomain c1.crash2.tld3 @$ns6			# 17 assert in rbtdb.c
537  nxdomain a0-1.tld2 +dnssec @$ns6		# 18 simple DO=1 without sigs
538  nxdomain a0-1s-cname.tld2s  +dnssec @$ns6	# 19
539  drop a3-8.tld2 any @$ns6			# 20 drop
540  end_group
541  ckstatsrange $ns3 test1 ns3 22 30
542  ckstats $ns5 test1 ns5 0
543  ckstats $ns6 test1 ns6 0
544
545  start_group "IP rewrites" test2
546  nodata a3-1.tld2				# 1 NODATA
547  nochange a3-2.tld2				# 2 no policy record so no change
548  nochange a4-1.tld2				# 3 obsolete PASSTHRU record style
549  nxdomain a4-2.tld2				# 4
550  nochange a4-2.tld2 -taaaa			# 5 no A => no policy rewrite
551  nochange a4-2.tld2 -ttxt			# 6 no A => no policy rewrite
552  nxdomain a4-2.tld2 -tany			# 7 no A => no policy rewrite
553  nodata a4-3.tld2				# 8
554  nxdomain a3-1.tld2 -taaaa			# 9 IPv6 policy
555  nochange a4-1-aaaa.tld2 -taaaa		# 10
556  addr 127.0.0.1 a5-1-2.tld2			# 11 prefer smallest policy address
557  addr 127.0.0.1 a5-3.tld2			# 12 prefer first conflicting IP zone
558  nochange a5-4.tld2 +norecurse			# 13 check that RD=1 is required for #14
559  addr 14.14.14.14 a5-4.tld2			# 14 prefer QNAME to IP
560  nochange a4-4.tld2				# 15 PASSTHRU
561  nxdomain c2.crash2.tld3			# 16 assert in rbtdb.c
562  addr 127.0.0.17 "a4-4.tld2 -b $ns1"		# 17 client-IP address trigger
563  nxdomain a7-1.tld2				# 18 slave policy zone (RT34450)
564  # updating an response zone policy
565  cp ns2/blv2.tld2.db.in ns2/bl.tld2.db
566  rndc_reload ns2 $ns2 bl.tld2
567  ck_soa 2 bl.tld2 $ns3
568  nochange a7-1.tld2				# 19 PASSTHRU
569  # ensure that a clock tick has occured so that named will do the reload
570  sleep 1
571  cp ns2/blv3.tld2.db.in ns2/bl.tld2.db
572  rndc_reload ns2 $ns2 bl.tld2
573  ck_soa 3 bl.tld2 $ns3
574  nxdomain a7-1.tld2				# 20 slave policy zone (RT34450)
575  end_group
576  ckstats $ns3 test2 ns3 12
577
578  # check that IP addresses for previous group were deleted from the radix tree
579  start_group "radix tree deletions"
580  nochange a3-1.tld2
581  nochange a3-2.tld2
582  nochange a4-1.tld2
583  nochange a4-2.tld2
584  nochange a4-2.tld2 -taaaa
585  nochange a4-2.tld2 -ttxt
586  nochange a4-2.tld2 -tany
587  nochange a4-3.tld2
588  nochange a3-1.tld2 -tAAAA
589  nochange a4-1-aaaa.tld2 -tAAAA
590  nochange a5-1-2.tld2
591  end_group
592  ckstats $ns3 'radix tree deletions' ns3 0
593
594  # these tests assume "min-ns-dots 0"
595  start_group "NSDNAME rewrites" test3
596  nochange a3-1.tld2				# 1
597  nochange a3-1.tld2 +dnssec			# 2 this once caused problems
598  nxdomain a3-1.sub1.tld2			# 3 NXDOMAIN *.sub1.tld2 by NSDNAME
599  nxdomain a3-1.subsub.sub1.tld2		# 4
600  nxdomain a3-1.subsub.sub1.tld2 -tany		# 5
601  addr 12.12.12.12 a4-2.subsub.sub2.tld2	# 6 walled garden for *.sub2.tld2
602  nochange a3-2.tld2.				# 7 exempt rewrite by name
603  nochange a0-1.tld2.				# 8 exempt rewrite by address block
604  addr 12.12.12.12 a4-1.tld2			# 9 prefer QNAME policy to NSDNAME
605  addr 127.0.0.1 a3-1.sub3.tld2			# 10 prefer policy for largest NSDNAME
606  addr 127.0.0.2 a3-1.subsub.sub3.tld2		# 11
607  nxdomain xxx.crash1.tld2			# 12 dns_db_detachnode() crash
608  if [ "$mode" = dnsrps ]; then
609    addr 12.12.12.12 as-ns.tld5.		# 13 qname-as-ns
610  fi
611  end_group
612  if [ "$mode" = dnsrps ]; then
613    ckstats $ns3 test3 ns3 8
614  else
615    ckstats $ns3 test3 ns3 7
616  fi
617
618  # these tests assume "min-ns-dots 0"
619  start_group "NSIP rewrites" test4
620  nxdomain a3-1.tld2				# 1 NXDOMAIN for all of tld2
621  nochange a3-2.tld2.				# 2 exempt rewrite by name
622  nochange a0-1.tld2.				# 3 exempt rewrite by address block
623  nochange a3-1.tld4				# 4 different NS IP address
624  if [ "$mode" = dnsrps ]; then
625      addr 12.12.12.12 as-ns.tld5.		# 5 ip-as-ns
626  fi
627  end_group
628
629  start_group "walled garden NSIP rewrites" test4a
630  addr 41.41.41.41 a3-1.tld2			# 1 walled garden for all of tld2
631  addr 2041::41   'a3-1.tld2 AAAA'		# 2 walled garden for all of tld2
632  here a3-1.tld2 TXT <<'EOF'			# 3 text message for all of tld2
633    ;; status: NOERROR, x
634    a3-1.tld2.	    x	IN	TXT   "NSIP walled garden"
635EOF
636  end_group
637  if [ "$mode" = dnsrps ]; then
638    ckstats $ns3 test4 ns3 5
639  else
640    ckstats $ns3 test4 ns3 4
641  fi
642
643  # policies in ./test5 overridden by response-policy{} in ns3/named.conf
644  # and in ns5/named.conf
645  start_group "policy overrides" test5
646  addr 127.0.0.1 a3-1.tld2			# 1 bl-given
647  nochange a3-2.tld2				# 2 bl-passthru
648  nochange a3-3.tld2				# 3 bl-no-op (obsolete for passthru)
649  nochange a3-4.tld2				# 4 bl-disabled
650  nodata a3-5.tld2				# 5 bl-nodata zone recursive-only no
651  nodata a3-5.tld2 +norecurse			# 6 bl-nodata zone recursive-only no
652  nodata a3-5.tld2				# 7 bl-nodata not needed
653  nxdomain a3-5.tld2 +norecurse @$ns5		# 8 bl-nodata global recursive-only no
654  nxdomain a3-5.tld2s @$ns5			# 9 bl-nodata global break-dnssec
655  nxdomain a3-5.tld2s +dnssec @$ns5		# 10 bl-nodata global break-dnssec
656  nxdomain a3-6.tld2				# 11 bl-nxdomain
657  here a3-7.tld2 -tany <<'EOF'			# 12
658    ;; status: NOERROR, x
659    a3-7.tld2.	    x	IN	CNAME   txt-only.tld2.
660    txt-only.tld2.  x	IN	TXT     "txt-only-tld2"
661EOF
662  addr 58.58.58.58 a3-8.tld2			# 13 bl_wildcname
663  addr 59.59.59.59 a3-9.sub9.tld2		# 14 bl_wildcname
664  addr 12.12.12.12 a3-15.tld2			# 15 bl-garden via CNAME to a12.tld2
665  addr 127.0.0.16 a3-16.tld2 100		# 16 bl	max-policy-ttl 100
666  addr 17.17.17.17 "a3-17.tld2 @$ns5" 90	# 17 ns5 bl max-policy-ttl 90
667  drop a3-18.tld2 any				# 18 bl-drop
668  nxdomain TCP a3-19.tld2			# 19 bl-tcp-only
669  end_group
670  ckstats $ns3 test5 ns3 12
671  ckstats $ns5 test5 ns5 4
672
673  # check that miscellaneous bugs are still absent
674  start_group "crashes" test6
675  for Q in RRSIG SIG ANY 'ANY +dnssec'; do
676    nocrash a3-1.tld2 -t$Q
677    nocrash a3-2.tld2 -t$Q
678    nocrash a3-5.tld2 -t$Q
679    nocrash www.redirect -t$Q
680    nocrash www.credirect -t$Q
681  done
682
683  # This is not a bug, because any data leaked by writing 24.4.3.2.10.rpz-ip
684  # (or whatever) is available by publishing "foo A 10.2.3.4" and then
685  # resolving foo.
686  # nxdomain 32.3.2.1.127.rpz-ip
687  end_group
688  ckstats $ns3 bugs ns3 8
689
690  # superficial test for major performance bugs
691  QPERF=`sh qperf.sh`
692  if test -n "$QPERF"; then
693    perf () {
694	date "+${TS}checking performance $1" | cat_i
695	# Dry run to prime everything
696	comment "before dry run $1"
697	$RNDCCMD $ns5 notrace
698	$QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p ${PORT} >/dev/null
699	comment "before real test $1"
700	PFILE="ns5/$2.perf"
701	$QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p ${PORT} >$PFILE
702	comment "after test $1"
703	X=`sed -n -e 's/.*Returned *\([^ ]*:\) *\([0-9]*\) .*/\1\2/p' $PFILE \
704		| tr '\n' ' '`
705	if test "$X" != "$3"; then
706	    setret "wrong results '$X' in $PFILE"
707	fi
708	ckalive $ns5 "failed; server #5 crashed"
709    }
710    trim () {
711	sed -n -e 's/.*Queries per second: *\([0-9]*\).*/\1/p' ns5/$1.perf
712    }
713
714    # get qps with rpz
715    perf 'with RPZ' rpz 'NOERROR:2900 NXDOMAIN:100 '
716    RPZ=`trim rpz`
717    # turn off rpz and measure qps again
718    echo "# RPZ off" >ns5/rpz-switch
719    RNDCCMD_OUT=`$RNDCCMD $ns5 reload`
720    perf 'without RPZ' norpz 'NOERROR:3000 '
721    NORPZ=`trim norpz`
722
723    PERCENT=`expr \( "$RPZ" \* 100 + \( $NORPZ / 2 \) \) / $NORPZ`
724    echo_i "$RPZ qps with RPZ is $PERCENT% of $NORPZ qps without RPZ"
725
726    MIN_PERCENT=30
727    if test "$PERCENT" -lt $MIN_PERCENT; then
728	echo_i "$RPZ qps with rpz or $PERCENT% is below $MIN_PERCENT% of $NORPZ qps"
729    fi
730
731    if test "$PERCENT" -ge 100; then
732	echo_i "$RPZ qps with RPZ or $PERCENT% of $NORPZ qps without RPZ is too high"
733    fi
734
735    ckstats $ns5 performance ns5 200
736
737  else
738    echo_i "performance not checked; queryperf not available"
739  fi
740
741  if [ "$mode" = dnsrps ]; then
742    echo_i "checking that dnsrpzd is automatically restarted"
743    OLD_PID=`cat dnsrpzd.pid`
744    $KILL "$OLD_PID"
745    n=0
746    while true; do
747	NEW_PID=`cat dnsrpzd.pid 2>/dev/null`
748	if test -n "$NEW_PID" -a "0$OLD_PID" -ne "0$NEW_PID"; then
749	    #echo "OLD_PID=$OLD_PID  NEW_PID=$NEW_PID"
750	    break;
751	fi
752	$DIG -p ${PORT} +short +norecurse a0-1.tld2 @$ns3 >/dev/null
753	n=`expr $n + 1`
754	if test "$n" -gt $TEN_SECS; then
755	    setret "dnsrpzd did not restart"
756	    break
757	fi
758	$WAIT_CMD
759    done
760  fi
761
762  # reconfigure the ns5 master server without the fast-exire zone, so
763  # it can't be refreshed on ns3, and will expire in 5 seconds.
764  cat /dev/null > ns5/expire.conf
765  rndc_reconfig ns5 10.53.0.5
766
767  # restart the main test RPZ server to see if that creates a core file
768  if test -z "$HAVE_CORE"; then
769    $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3
770    restart 3 "rebuild-bl-rpz"
771    HAVE_CORE=`find ns* -name '*core*' -print`
772    test -z "$HAVE_CORE" || setret "found $HAVE_CORE; memory leak?"
773  fi
774
775  # look for complaints from lib/dns/rpz.c and bin/name/query.c
776  for runfile in ns*/named.run; do
777    EMSGS=`nextpart $runfile | egrep -l 'invalid rpz|rpz.*failed'`
778    if test -n "$EMSGS"; then
779      setret "error messages in $runfile starting with:"
780      egrep 'invalid rpz|rpz.*failed' ns*/named.run | \
781              sed -e '10,$d' -e 's/^//' | cat_i
782    fi
783  done
784
785  if [ native = "$mode" ]; then
786    # restart the main test RPZ server with a bad zone.
787    t=`expr $t + 1`
788    echo_i "checking that ns3 with broken rpz does not crash (${t})"
789    $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3
790    cp ns3/broken.db.in ns3/bl.db
791    restart 3 # do not rebuild rpz zones
792    nocrash a3-1.tld2 -tA
793    $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3
794    restart 3 "rebuild-bl-rpz"
795
796    # reload a RPZ zone that is now deliberately broken.
797    t=`expr $t + 1`
798    echo_i "checking rpz failed update will keep previous rpz rules (${t})"
799    $DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t.before
800    grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.before > /dev/null || setret "failed"
801    cp ns3/broken.db.in ns3/manual-update-rpz.db
802    rndc_reload ns3 $ns3 manual-update-rpz
803    sleep 1
804    # ensure previous RPZ rules still apply.
805    $DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t.after
806    grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.after > /dev/null || setret "failed"
807  fi
808
809  t=`expr $t + 1`
810  echo_i "checking that ttl values are not zeroed when qtype is '*' (${t})"
811  $DIG +noall +answer -p ${PORT} @$ns3 any a3-2.tld2 > dig.out.$t
812  ttl=`awk '/a3-2 tld2 text/ {print $2}' dig.out.$t`
813  if test ${ttl:=0} -eq 0; then setret "failed"; fi
814
815  t=`expr $t + 1`
816  echo_i "checking rpz updates/transfers with parent nodes added after children (${t})"
817  # regression test for RT #36272: the success condition
818  # is the slave server not crashing.
819  for i in 1 2 3 4 5; do
820    nsd $ns5 add example.com.policy1. '*.example.com.policy1.'
821    nsd $ns5 delete example.com.policy1. '*.example.com.policy1.'
822  done
823  for i in 1 2 3 4 5; do
824    nsd $ns5 add '*.example.com.policy1.' example.com.policy1.
825    nsd $ns5 delete '*.example.com.policy1.' example.com.policy1.
826  done
827
828  t=`expr $t + 1`
829  echo_i "checking that going from an empty policy zone works (${t})"
830  nsd $ns5 add '*.x.servfail.policy2.' x.servfail.policy2.
831  sleep 1
832  rndc_reload ns7 $ns7 policy2
833  $DIG z.x.servfail -p ${PORT} @$ns7 > dig.out.${t}
834  grep NXDOMAIN dig.out.${t} > /dev/null || setret "failed"
835
836  t=`expr $t + 1`
837  echo_i "checking that "add-soa no" at rpz zone level works (${t})"
838  $DIG z.x.servfail -p ${PORT} @$ns7 > dig.out.${t}
839  grep SOA dig.out.${t} > /dev/null && setret "failed"
840
841  if [ native = "$mode" ]; then
842    t=`expr $t + 1`
843    echo_i "checking that "add-soa yes" at response-policy level works (${t})"
844    $DIG walled.tld2 -p ${PORT} +noall +add @$ns3 > dig.out.${t}
845    grep "^manual-update-rpz\..*SOA" dig.out.${t} > /dev/null || setret "failed"
846  fi
847
848  if [ native = "$mode" ]; then
849    t=`expr $t + 1`
850    echo_i "checking that "add-soa unset" works (${t})"
851    $DIG walled.tld2 -p ${PORT} +noall +add @$ns8 > dig.out.${t}
852    grep "^manual-update-rpz\..*SOA" dig.out.${t} > /dev/null || setret "failed"
853  fi
854
855  # dnsrps does not allow NS RRs in policy zones, so this check
856  # with dnsrps results in no rewriting.
857  if [ native = "$mode" ]; then
858    t=`expr $t + 1`
859    echo_i "checking rpz with delegation fails correctly (${t})"
860    $DIG -p ${PORT} @$ns3 ns example.com > dig.out.$t
861    grep "status: SERVFAIL" dig.out.$t > /dev/null || setret "failed"
862
863    t=`expr $t + 1`
864    echo_i "checking policies from expired zone are no longer in effect ($t)"
865    $DIG -p ${PORT} @$ns3 a expired > dig.out.$t
866    grep "expired.*10.0.0.10" dig.out.$t > /dev/null && setret "failed"
867    grep "fast-expire/IN: response-policy zone expired" ns3/named.run > /dev/null || setret "failed"
868  fi
869
870  # RPZ 'CNAME *.' (NODATA) trumps DNS64.  Test against various DNS64 senarios.
871  for label in a-only no-a-no-aaaa a-plus-aaaa
872  do
873    for type in AAAA A
874    do
875      t=`expr $t + 1`
876      case $label in
877      a-only)
878	echo_i "checking rpz 'CNAME *.' (NODATA) with dns64, $type lookup with A-only (${t})"
879	;;
880      no-a-no-aaaa)
881	echo_i "checking rpz 'CNAME *.' (NODATA) with dns64, $type lookup with no A or AAAA (${t})"
882	;;
883      a-plus-aaaa)
884	echo_i "checking rpz 'CNAME *.' (NODATA) with dns64, $type lookup with A and AAAA (${t})"
885	;;
886      esac
887      ret=0
888      $DIG ${label}.example -p ${PORT} $type @10.53.0.9 > dig.out.${t}
889      grep "status: NOERROR" dig.out.$t > /dev/null || ret=1
890      grep "ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 2$" dig.out.$t > /dev/null || ret=1
891      grep "^rpz"  dig.out.$t > /dev/null || ret=1
892      [ $ret -eq 0 ] || echo_i "failed"
893      status=`expr $status + $ret`
894    done
895  done
896
897  [ $status -ne 0 ] && pf=fail || pf=pass
898  case $mode in
899  native)
900    native=$status
901    echo_i "status (native RPZ sub-test): $status ($pf)";;
902
903  dnsrps)
904    dnsrps=$status
905    echo_i "status (DNSRPS sub-test): $status ($pf)";;
906  *) echo_i "invalid test mode";;
907  esac
908done
909status=`expr ${native:-0} + ${dnsrps:-0}`
910
911[ $status -eq 0 ] || exit 1
912