xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/statschannel/tests.sh (revision 3f351f34c6d827cf017cdcff3543f6ec0c88b420)
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
14SYSTEMTESTTOP=..
15# shellcheck source=conf.sh
16. "$SYSTEMTESTTOP/conf.sh"
17
18DIGCMD="$DIG @10.53.0.2 -p ${PORT}"
19RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
20
21if ! $FEATURETEST --have-json-c
22then
23    unset PERL_JSON
24    echo_i "JSON was not configured; skipping" >&2
25elif $PERL -e 'use JSON;' 2>/dev/null
26then
27    PERL_JSON=1
28else
29    unset PERL_JSON
30    echo_i "JSON tests require JSON library; skipping" >&2
31fi
32
33if ! $FEATURETEST --have-libxml2
34then
35    unset PERL_XML
36    echo_i "XML was not configured; skipping" >&2
37elif $PERL -e 'use XML::Simple;' 2>/dev/null
38then
39    PERL_XML=1
40else
41    unset PERL_XML
42    echo_i "XML tests require XML::Simple; skipping" >&2
43fi
44
45if [ ! "$PERL_JSON" -a ! "$PERL_XML" ]; then
46    echo_i "skipping all tests"
47    exit 0
48fi
49
50
51getzones() {
52    sleep 1
53    echo_i "... using $1"
54    case $1 in
55        xml) path='xml/v3/zones' ;;
56        json) path='json/v1/zones' ;;
57        *) return 1 ;;
58    esac
59    file=`$PERL fetch.pl -p ${EXTRAPORT1} $path`
60    cp $file $file.$1.$3
61    $PERL zones-${1}.pl $file $2 2>/dev/null | sort > zones.out.$3
62    result=$?
63    return $result
64}
65
66# TODO: Move loadkeys_on to conf.sh.common
67loadkeys_on() {
68    nsidx=$1
69    zone=$2
70    nextpart ns${nsidx}/named.run > /dev/null
71    $RNDCCMD 10.53.0.${nsidx} loadkeys ${zone} | sed "s/^/ns${nsidx} /" | cat_i
72    wait_for_log 20 "next key event" ns${nsidx}/named.run
73}
74
75status=0
76n=1
77ret=0
78echo_i "checking consistency between named.stats and xml/json ($n)"
79rm -f ns2/named.stats
80$DIGCMD +tcp example ns > dig.out.$n || ret=1
81$RNDCCMD 10.53.0.2 stats 2>&1 | sed 's/^/I:ns1 /'
82query_count=`awk '/QUERY/ {print $1}' ns2/named.stats`
83txt_count=`awk '/TXT/ {print $1}' ns2/named.stats`
84noerror_count=`awk '/NOERROR/ {print $1}' ns2/named.stats`
85if [ $PERL_XML ]; then
86    file=`$PERL fetch.pl -p ${EXTRAPORT1} xml/v3/server`
87    mv $file xml.stats
88    $PERL server-xml.pl > xml.fmtstats 2> /dev/null
89    xml_query_count=`awk '/opcode QUERY/ { print $NF }' xml.fmtstats`
90    xml_query_count=${xml_query_count:-0}
91    [ "$query_count" -eq "$xml_query_count" ] || ret=1
92    xml_txt_count=`awk '/qtype TXT/ { print $NF }' xml.fmtstats`
93    xml_txt_count=${xml_txt_count:-0}
94    [ "$txt_count" -eq "$xml_txt_count" ] || ret=1
95    xml_noerror_count=`awk '/rcode NOERROR/ { print $NF }' xml.fmtstats`
96    xml_noerror_count=${xml_noerror_count:-0}
97    [ "$noerror_count" -eq "$xml_noerror_count" ] || ret=1
98fi
99if [ $PERL_JSON ]; then
100    file=`$PERL fetch.pl -p ${EXTRAPORT1} json/v1/server`
101    mv $file json.stats
102    $PERL server-json.pl > json.fmtstats 2> /dev/null
103    json_query_count=`awk '/opcode QUERY/ { print $NF }' json.fmtstats`
104    json_query_count=${json_query_count:-0}
105    [ "$query_count" -eq "$json_query_count" ] || ret=1
106    json_txt_count=`awk '/qtype TXT/ { print $NF }' json.fmtstats`
107    json_txt_count=${json_txt_count:-0}
108    [ "$txt_count" -eq "$json_txt_count" ] || ret=1
109    json_noerror_count=`awk '/rcode NOERROR/ { print $NF }' json.fmtstats`
110    json_noerror_count=${json_noerror_count:-0}
111    [ "$noerror_count" -eq "$json_noerror_count" ] || ret=1
112fi
113if [ $ret != 0 ]; then echo_i "failed"; fi
114status=`expr $status + $ret`
115n=`expr $n + 1`
116
117ret=0
118echo_i "checking malloced memory statistics xml/json ($n)"
119if [ $PERL_XML ]; then
120    file=`$PERL fetch.pl -p ${EXTRAPORT1} xml/v3/mem`
121    mv $file xml.mem
122    $PERL mem-xml.pl $file > xml.fmtmem
123    grep "'Malloced' => '[0-9][0-9]*'" xml.fmtmem > /dev/null || ret=1
124    grep "'malloced' => '[0-9][0-9]*'" xml.fmtmem > /dev/null || ret=1
125    grep "'maxmalloced' => '[0-9][0-9]*'" xml.fmtmem > /dev/null || ret=1
126fi
127if [ $PERL_JSON ]; then
128    file=`$PERL fetch.pl -p ${EXTRAPORT1} json/v1/mem`
129    mv $file json.mem
130    grep '"malloced":[0-9][0-9]*,' json.mem > /dev/null || ret=1
131    grep '"maxmalloced":[0-9][0-9]*,' json.mem > /dev/null || ret=1
132    grep '"Malloced":[0-9][0-9]*,' json.mem > /dev/null || ret=1
133fi
134if [ $ret != 0 ]; then echo_i "failed"; fi
135status=`expr $status + $ret`
136n=`expr $n + 1`
137
138echo_i "checking consistency between regular and compressed output ($n)"
139for i in 1 2 3 4 5; do
140	ret=0
141	if $FEATURETEST --have-libxml2;
142	then
143		URL=http://10.53.0.2:${EXTRAPORT1}/xml/v3/server
144		filter_str='s#<current-time>.*</current-time>##g'
145	else
146		URL=http://10.53.0.2:${EXTRAPORT1}/json/v1/server
147		filter_str='s#"current-time.*",##g'
148	fi
149	$CURL -D regular.headers $URL 2>/dev/null | \
150		sed -e "$filter_str" > regular.out
151	$CURL -D compressed.headers --compressed $URL 2>/dev/null | \
152		sed -e "$filter_str" > compressed.out
153	diff regular.out compressed.out >/dev/null || ret=1
154	if [ $ret != 0 ]; then
155		echo_i "failed on try $i, probably a timing issue, trying again"
156		sleep 1
157	else
158		break
159	fi
160done
161
162status=`expr $status + $ret`
163n=`expr $n + 1`
164
165ret=0
166echo_i "checking if compressed output is really compressed ($n)"
167if $FEATURETEST --with-zlib;
168then
169    REGSIZE=`cat regular.headers | \
170	grep -i Content-Length | sed -e "s/.*: \([0-9]*\).*/\1/"`
171    COMPSIZE=`cat compressed.headers | \
172	grep -i Content-Length | sed -e "s/.*: \([0-9]*\).*/\1/"`
173    if [ ! `expr $REGSIZE / $COMPSIZE` -gt 2 ]; then
174	ret=1
175    fi
176else
177    echo_i "skipped"
178fi
179if [ $ret != 0 ]; then echo_i "failed"; fi
180status=`expr $status + $ret`
181n=`expr $n + 1`
182
183# Test dnssec sign statistics.
184zone="dnssec"
185sign_prefix="dnssec-sign operations"
186refresh_prefix="dnssec-refresh operations"
187ksk_id=`cat ns2/$zone.ksk.id`
188zsk_id=`cat ns2/$zone.zsk.id`
189
190# Test sign operations for scheduled resigning.
191ret=0
192# The dnssec zone has 10 RRsets to sign (including NSEC) with the ZSK and one
193# RRset (DNSKEY) with the KSK. So starting named with signatures that expire
194# almost right away, this should trigger 10 zsk and 1 ksk sign operations.
195echo "${refresh_prefix} ${zsk_id}: 10" > zones.expect
196echo "${refresh_prefix} ${ksk_id}: 1" >> zones.expect
197echo "${sign_prefix} ${zsk_id}: 10" >> zones.expect
198echo "${sign_prefix} ${ksk_id}: 1" >> zones.expect
199cat zones.expect | sort > zones.expect.$n
200rm -f zones.expect
201# Fetch and check the dnssec sign statistics.
202echo_i "fetching zone '$zone' stats data after zone maintenance at startup ($n)"
203if [ $PERL_XML ]; then
204    getzones xml $zone x$n || ret=1
205    cmp zones.out.x$n zones.expect.$n || ret=1
206fi
207if [ $PERL_JSON ]; then
208    getzones json 0 j$n || ret=1
209    cmp zones.out.j$n zones.expect.$n || ret=1
210fi
211if [ $ret != 0 ]; then echo_i "failed"; fi
212status=`expr $status + $ret`
213n=`expr $n + 1`
214
215# Test sign operations after dynamic update.
216ret=0
217(
218# Update dnssec zone to trigger signature creation.
219echo zone $zone
220echo server 10.53.0.2 "$PORT"
221echo update add $zone. 300 in txt "nsupdate added me"
222echo send
223) | $NSUPDATE
224# This should trigger the resign of SOA, TXT and NSEC (+3 zsk).
225echo "${refresh_prefix} ${zsk_id}: 10" > zones.expect
226echo "${refresh_prefix} ${ksk_id}: 1" >> zones.expect
227echo "${sign_prefix} ${zsk_id}: 13" >> zones.expect
228echo "${sign_prefix} ${ksk_id}: 1" >> zones.expect
229cat zones.expect | sort > zones.expect.$n
230rm -f zones.expect
231# Fetch and check the dnssec sign statistics.
232echo_i "fetching zone '$zone' stats data after dynamic update ($n)"
233if [ $PERL_XML ]; then
234    getzones xml $zone x$n || ret=1
235    cmp zones.out.x$n zones.expect.$n || ret=1
236fi
237if [ $PERL_JSON ]; then
238    getzones json 0 j$n || ret=1
239    cmp zones.out.j$n zones.expect.$n || ret=1
240fi
241if [ $ret != 0 ]; then echo_i "failed"; fi
242status=`expr $status + $ret`
243n=`expr $n + 1`
244
245# Test sign operations of KSK.
246ret=0
247echo_i "fetch zone '$zone' stats data after updating DNSKEY RRset ($n)"
248# Add a standby DNSKEY, this triggers resigning the DNSKEY RRset.
249zsk=$("$KEYGEN" -K ns2 -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
250$SETTIME -K ns2 -P now -A never $zsk.key > /dev/null
251loadkeys_on 2 $zone || ret=1
252# This should trigger the resign of SOA (+1 zsk) and DNSKEY (+1 ksk).
253echo "${refresh_prefix} ${zsk_id}: 11" > zones.expect
254echo "${refresh_prefix} ${ksk_id}: 2" >> zones.expect
255echo "${sign_prefix} ${zsk_id}: 14" >> zones.expect
256echo "${sign_prefix} ${ksk_id}: 2" >> zones.expect
257cat zones.expect | sort > zones.expect.$n
258rm -f zones.expect
259# Fetch and check the dnssec sign statistics.
260if [ $PERL_XML ]; then
261    getzones xml $zone x$n || ret=1
262    cmp zones.out.x$n zones.expect.$n || ret=1
263fi
264if [ $PERL_JSON ]; then
265    getzones json 0 j$n || ret=1
266    cmp zones.out.j$n zones.expect.$n || ret=1
267fi
268if [ $ret != 0 ]; then echo_i "failed"; fi
269status=`expr $status + $ret`
270n=`expr $n + 1`
271
272# Test sign operations for scheduled resigning (many keys).
273ret=0
274zone="manykeys"
275ksk8_id=`cat ns2/$zone.ksk8.id`
276zsk8_id=`cat ns2/$zone.zsk8.id`
277ksk13_id=`cat ns2/$zone.ksk13.id`
278zsk13_id=`cat ns2/$zone.zsk13.id`
279ksk14_id=`cat ns2/$zone.ksk14.id`
280zsk14_id=`cat ns2/$zone.zsk14.id`
281num_ids=$( (echo $ksk8_id; echo $zsk8_id; echo $ksk13_id; echo $zsk13_id; echo $ksk14_id; echo $zsk14_id;) | sort -u | wc -l)
282# The dnssec zone has 10 RRsets to sign (including NSEC) with the ZSKs and one
283# RRset (DNSKEY) with the KSKs. So starting named with signatures that expire
284# almost right away, this should trigger 10 zsk and 1 ksk sign operations per
285# key.
286echo "${refresh_prefix} ${zsk8_id}: 10" > zones.expect
287echo "${refresh_prefix} ${zsk13_id}: 10" >> zones.expect
288echo "${refresh_prefix} ${zsk14_id}: 10" >> zones.expect
289echo "${refresh_prefix} ${ksk8_id}: 1" >> zones.expect
290echo "${refresh_prefix} ${ksk13_id}: 1" >> zones.expect
291echo "${refresh_prefix} ${ksk14_id}: 1" >> zones.expect
292echo "${sign_prefix} ${zsk8_id}: 10" >> zones.expect
293echo "${sign_prefix} ${zsk13_id}: 10" >> zones.expect
294echo "${sign_prefix} ${zsk14_id}: 10" >> zones.expect
295echo "${sign_prefix} ${ksk8_id}: 1" >> zones.expect
296echo "${sign_prefix} ${ksk13_id}: 1" >> zones.expect
297echo "${sign_prefix} ${ksk14_id}: 1" >> zones.expect
298cat zones.expect | sort > zones.expect.$n
299rm -f zones.expect
300# Fetch and check the dnssec sign statistics.
301echo_i "fetching zone '$zone' stats data after zone maintenance at startup ($n)"
302if test $num_ids -eq 6
303then
304    if [ $PERL_XML ]; then
305        getzones xml $zone x$n || ret=1
306        cmp zones.out.x$n zones.expect.$n || ret=1
307    fi
308    if [ $PERL_JSON ]; then
309        getzones json 2 j$n || ret=1
310        cmp zones.out.j$n zones.expect.$n || ret=1
311    fi
312    if [ $ret != 0 ]; then echo_i "failed"; fi
313else
314    echo_i "skipped: duplicate key id detected (fixed in BIND 9.19)"
315fi
316status=`expr $status + $ret`
317n=`expr $n + 1`
318
319# Test sign operations after dynamic update (many keys).
320ret=0
321(
322# Update dnssec zone to trigger signature creation.
323echo zone $zone
324echo server 10.53.0.2 "$PORT"
325echo update add $zone. 300 in txt "nsupdate added me"
326echo send
327) | $NSUPDATE
328# This should trigger the resign of SOA, TXT and NSEC (+3 zsk).
329echo "${refresh_prefix} ${zsk8_id}: 10" > zones.expect
330echo "${refresh_prefix} ${zsk13_id}: 10" >> zones.expect
331echo "${refresh_prefix} ${zsk14_id}: 10" >> zones.expect
332echo "${refresh_prefix} ${ksk8_id}: 1" >> zones.expect
333echo "${refresh_prefix} ${ksk13_id}: 1" >> zones.expect
334echo "${refresh_prefix} ${ksk14_id}: 1" >> zones.expect
335echo "${sign_prefix} ${zsk8_id}: 13" >> zones.expect
336echo "${sign_prefix} ${zsk13_id}: 13" >> zones.expect
337echo "${sign_prefix} ${zsk14_id}: 13" >> zones.expect
338echo "${sign_prefix} ${ksk8_id}: 1" >> zones.expect
339echo "${sign_prefix} ${ksk13_id}: 1" >> zones.expect
340echo "${sign_prefix} ${ksk14_id}: 1" >> zones.expect
341cat zones.expect | sort > zones.expect.$n
342rm -f zones.expect
343# Fetch and check the dnssec sign statistics.
344echo_i "fetching zone '$zone' stats data after dynamic update ($n)"
345if test $num_ids -eq 6
346then
347    if [ $PERL_XML ]; then
348        getzones xml $zone x$n || ret=1
349        cmp zones.out.x$n zones.expect.$n || ret=1
350    fi
351    if [ $PERL_JSON ]; then
352        getzones json 2 j$n || ret=1
353        cmp zones.out.j$n zones.expect.$n || ret=1
354    fi
355    if [ $ret != 0 ]; then echo_i "failed"; fi
356else
357    echo_i "skipped: duplicate key id detected (fixed in BIND 9.19)"
358fi
359status=`expr $status + $ret`
360n=`expr $n + 1`
361
362# Test sign operations after dnssec-policy change (removing keys).
363ret=0
364copy_setports ns2/named2.conf.in ns2/named.conf
365$RNDCCMD 10.53.0.2 reload 2>&1 | sed 's/^/I:ns2 /'
366# This should trigger the resign of DNSKEY (+1 ksk), and SOA, NSEC,
367# TYPE65534 (+3 zsk). The dnssec-sign statistics for the removed keys should
368# be cleared and thus no longer visible. But NSEC and SOA are (mistakenly)
369# counted double, one time because of zone_resigninc and one time because of
370# zone_nsec3chain. So +5 zsk in total.
371echo "${refresh_prefix} ${zsk8_id}: 15" > zones.expect
372echo "${refresh_prefix} ${ksk8_id}: 2" >> zones.expect
373echo "${sign_prefix} ${zsk8_id}: 18" >> zones.expect
374echo "${sign_prefix} ${ksk8_id}: 2" >> zones.expect
375cat zones.expect | sort > zones.expect.$n
376rm -f zones.expect
377# Fetch and check the dnssec sign statistics.
378echo_i "fetching zone '$zone' stats data after dnssec-policy change ($n)"
379if [ $PERL_XML ]; then
380    getzones xml $zone x$n || ret=1
381    cmp zones.out.x$n zones.expect.$n || ret=1
382fi
383if [ $PERL_JSON ]; then
384    getzones json 2 j$n || ret=1
385    cmp zones.out.j$n zones.expect.$n || ret=1
386fi
387if [ $ret != 0 ]; then echo_i "failed"; fi
388status=`expr $status + $ret`
389n=`expr $n + 1`
390
391echo_i "exit status: $status"
392[ $status -eq 0 ] || exit 1
393