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 [ ! "$HAVEJSONSTATS" ] 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 [ ! "$HAVEXMLSTATS" ] 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 [ "$HAVEXMLSTATS" ]; 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 [ "$HAVEZLIB" ]; 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` 281# The dnssec zone has 10 RRsets to sign (including NSEC) with the ZSKs and one 282# RRset (DNSKEY) with the KSKs. So starting named with signatures that expire 283# almost right away, this should trigger 10 zsk and 1 ksk sign operations per 284# key. 285echo "${refresh_prefix} ${zsk8_id}: 10" > zones.expect 286echo "${refresh_prefix} ${zsk13_id}: 10" >> zones.expect 287echo "${refresh_prefix} ${zsk14_id}: 10" >> zones.expect 288echo "${refresh_prefix} ${ksk8_id}: 1" >> zones.expect 289echo "${refresh_prefix} ${ksk13_id}: 1" >> zones.expect 290echo "${refresh_prefix} ${ksk14_id}: 1" >> zones.expect 291echo "${sign_prefix} ${zsk8_id}: 10" >> zones.expect 292echo "${sign_prefix} ${zsk13_id}: 10" >> zones.expect 293echo "${sign_prefix} ${zsk14_id}: 10" >> zones.expect 294echo "${sign_prefix} ${ksk8_id}: 1" >> zones.expect 295echo "${sign_prefix} ${ksk13_id}: 1" >> zones.expect 296echo "${sign_prefix} ${ksk14_id}: 1" >> zones.expect 297cat zones.expect | sort > zones.expect.$n 298rm -f zones.expect 299# Fetch and check the dnssec sign statistics. 300echo_i "fetching zone '$zone' stats data after zone maintenance at startup ($n)" 301if [ $PERL_XML ]; then 302 getzones xml $zone x$n || ret=1 303 cmp zones.out.x$n zones.expect.$n || ret=1 304fi 305if [ $PERL_JSON ]; then 306 getzones json 2 j$n || ret=1 307 cmp zones.out.j$n zones.expect.$n || ret=1 308fi 309if [ $ret != 0 ]; then echo_i "failed"; fi 310status=`expr $status + $ret` 311n=`expr $n + 1` 312 313# Test sign operations after dynamic update (many keys). 314ret=0 315( 316# Update dnssec zone to trigger signature creation. 317echo zone $zone 318echo server 10.53.0.2 "$PORT" 319echo update add $zone. 300 in txt "nsupdate added me" 320echo send 321) | $NSUPDATE 322# This should trigger the resign of SOA, TXT and NSEC (+3 zsk). 323echo "${refresh_prefix} ${zsk8_id}: 10" > zones.expect 324echo "${refresh_prefix} ${zsk13_id}: 10" >> zones.expect 325echo "${refresh_prefix} ${zsk14_id}: 10" >> zones.expect 326echo "${refresh_prefix} ${ksk8_id}: 1" >> zones.expect 327echo "${refresh_prefix} ${ksk13_id}: 1" >> zones.expect 328echo "${refresh_prefix} ${ksk14_id}: 1" >> zones.expect 329echo "${sign_prefix} ${zsk8_id}: 13" >> zones.expect 330echo "${sign_prefix} ${zsk13_id}: 13" >> zones.expect 331echo "${sign_prefix} ${zsk14_id}: 13" >> zones.expect 332echo "${sign_prefix} ${ksk8_id}: 1" >> zones.expect 333echo "${sign_prefix} ${ksk13_id}: 1" >> zones.expect 334echo "${sign_prefix} ${ksk14_id}: 1" >> zones.expect 335cat zones.expect | sort > zones.expect.$n 336rm -f zones.expect 337# Fetch and check the dnssec sign statistics. 338echo_i "fetching zone '$zone' stats data after dynamic update ($n)" 339if [ $PERL_XML ]; then 340 getzones xml $zone x$n || ret=1 341 cmp zones.out.x$n zones.expect.$n || ret=1 342fi 343if [ $PERL_JSON ]; then 344 getzones json 2 j$n || ret=1 345 cmp zones.out.j$n zones.expect.$n || ret=1 346fi 347if [ $ret != 0 ]; then echo_i "failed"; fi 348status=`expr $status + $ret` 349n=`expr $n + 1` 350 351# Test sign operations after dnssec-policy change (removing keys). 352ret=0 353copy_setports ns2/named2.conf.in ns2/named.conf 354$RNDCCMD 10.53.0.2 reload 2>&1 | sed 's/^/I:ns2 /' 355# This should trigger the resign of DNSKEY (+1 ksk), and SOA, NSEC, 356# TYPE65534 (+3 zsk). The dnssec-sign statistics for the removed keys should 357# be cleared and thus no longer visible. But NSEC and SOA are (mistakenly) 358# counted double, one time because of zone_resigninc and one time because of 359# zone_nsec3chain. So +5 zsk in total. 360echo "${refresh_prefix} ${zsk8_id}: 15" > zones.expect 361echo "${refresh_prefix} ${ksk8_id}: 2" >> zones.expect 362echo "${sign_prefix} ${zsk8_id}: 18" >> zones.expect 363echo "${sign_prefix} ${ksk8_id}: 2" >> zones.expect 364cat zones.expect | sort > zones.expect.$n 365rm -f zones.expect 366# Fetch and check the dnssec sign statistics. 367echo_i "fetching zone '$zone' stats data after dnssec-policy change ($n)" 368if [ $PERL_XML ]; then 369 getzones xml $zone x$n || ret=1 370 cmp zones.out.x$n zones.expect.$n || ret=1 371fi 372if [ $PERL_JSON ]; then 373 getzones json 2 j$n || ret=1 374 cmp zones.out.j$n zones.expect.$n || ret=1 375fi 376if [ $ret != 0 ]; then echo_i "failed"; fi 377status=`expr $status + $ret` 378n=`expr $n + 1` 379 380echo_i "exit status: $status" 381[ $status -eq 0 ] || exit 1 382