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. ../conf.sh 17 18status=0 19n=0 20 21RNDCOPTS="-c ../_common/rndc.conf -s 10.53.0.2 -p ${CONTROLPORT}" 22DIGOPTS="+nosea +nocomm +nocmd +noquest +noadd +noauth +nocomm \ 23 +nostat @10.53.0.2 -p ${PORT}" 24 25# fill the cache with nodes from flushtest.example zone 26load_cache() { 27 # empty all existing cache data 28 $RNDC $RNDCOPTS flush 29 30 # load the positive cache entries 31 $DIG $DIGOPTS -f - <<EOF >/dev/null 2>&1 32txt top1.flushtest.example 33txt second1.top1.flushtest.example 34txt third1.second1.top1.flushtest.example 35txt third2.second1.top1.flushtest.example 36txt second2.top1.flushtest.example 37txt second3.top1.flushtest.example 38txt second1.top2.flushtest.example 39txt second2.top2.flushtest.example 40txt second3.top2.flushtest.example 41txt top3.flushtest.example 42txt second1.top3.flushtest.example 43txt third1.second1.top3.flushtest.example 44txt third2.second1.top3.flushtest.example 45txt third1.second2.top3.flushtest.example 46txt third2.second2.top3.flushtest.example 47txt second3.top3.flushtest.example 48EOF 49 50 # load the negative cache entries 51 # nxrrset: 52 $DIG $DIGOPTS a third1.second1.top1.flushtest.example >/dev/null 53 # nxdomain: 54 $DIG $DIGOPTS txt top4.flushtest.example >/dev/null 55 # empty nonterminal: 56 $DIG $DIGOPTS txt second2.top3.flushtest.example >/dev/null 57 58 # sleep 2 seconds ensure the TTLs will be lower on cached data 59 sleep 2 60} 61 62dump_cache() { 63 rndc_dumpdb ns2 -cache _default 64} 65 66clear_cache() { 67 $RNDC $RNDCOPTS flush 68} 69 70in_cache() { 71 ttl=$($DIG $DIGOPTS "$@" | awk '{print $2}') 72 [ -z "$ttl" ] && { 73 ttl=$($DIG $DIGOPTS +noanswer +auth "$@" | awk '{print $2}') 74 [ "$ttl" -ge 3599 ] && return 1 75 return 0 76 } 77 [ "$ttl" -ge 3599 ] && return 1 78 return 0 79} 80 81# Extract records at and below name "$1" from the cache dump in file "$2". 82filter_tree() { 83 tree="$1" 84 file="$2" 85 perl -n -e ' 86 next if /^;/; 87 if (/'"$tree"'/ || (/^\t/ && $print)) { 88 $print = 1; 89 } else { 90 $print = 0; 91 } 92 print if $print; 93 ' "$file" 94} 95 96n=$((n + 1)) 97echo_i "check correctness of routine cache cleaning ($n)" 98$DIG $DIGOPTS +tcp +keepopen -b 10.53.0.7 -f dig.batch >dig.out.ns2 || status=1 99 100digcomp --lc dig.out.ns2 knowngood.dig.out || status=1 101 102n=$((n + 1)) 103echo_i "only one tcp socket was used ($n)" 104tcpclients=$(awk '$3 == "client" && $5 ~ /10.53.0.7#[0-9]*:/ {print $5}' ns2/named.run | sort | uniq -c | wc -l) 105 106test $tcpclients -eq 1 || { 107 status=1 108 echo_i "failed" 109} 110 111n=$((n + 1)) 112echo_i "reset and check that records are correctly cached initially ($n)" 113ret=0 114load_cache 115dump_cache 116nrecords=$(filter_tree flushtest.example ns2/named_dump.db.test$n | grep -E '(TXT|ANY)' | wc -l) 117[ $nrecords -eq 18 ] || { 118 ret=1 119 echo_i "found $nrecords records expected 18" 120} 121if [ $ret != 0 ]; then echo_i "failed"; fi 122status=$((status + ret)) 123 124n=$((n + 1)) 125echo_i "check flushing of the full cache ($n)" 126ret=0 127clear_cache 128dump_cache 129nrecords=$(filter_tree flushtest.example ns2/named_dump.db.test$n | wc -l) 130[ $nrecords -eq 0 ] || ret=1 131if [ $ret != 0 ]; then echo_i "failed"; fi 132status=$((status + ret)) 133 134n=$((n + 1)) 135echo_i "check flushing of individual nodes (interior node) ($n)" 136ret=0 137clear_cache 138load_cache 139# interior node 140in_cache txt top1.flushtest.example || ret=1 141$RNDC $RNDCOPTS flushname top1.flushtest.example 142in_cache txt top1.flushtest.example && ret=1 143if [ $ret != 0 ]; then echo_i "failed"; fi 144status=$((status + ret)) 145 146n=$((n + 1)) 147echo_i "check flushing of individual nodes (leaf node, under the interior node) ($n)" 148ret=0 149# leaf node, under the interior node (should still exist) 150in_cache txt third2.second1.top1.flushtest.example || ret=1 151$RNDC $RNDCOPTS flushname third2.second1.top1.flushtest.example 152in_cache txt third2.second1.top1.flushtest.example && ret=1 153if [ $ret != 0 ]; then echo_i "failed"; fi 154status=$((status + ret)) 155 156n=$((n + 1)) 157echo_i "check flushing of individual nodes (another leaf node, with both positive and negative cache entries) ($n)" 158ret=0 159# another leaf node, with both positive and negative cache entries 160in_cache a third1.second1.top1.flushtest.example || ret=1 161in_cache txt third1.second1.top1.flushtest.example || ret=1 162$RNDC $RNDCOPTS flushname third1.second1.top1.flushtest.example 163in_cache a third1.second1.top1.flushtest.example && ret=1 164in_cache txt third1.second1.top1.flushtest.example && ret=1 165if [ $ret != 0 ]; then echo_i "failed"; fi 166status=$((status + ret)) 167 168n=$((n + 1)) 169echo_i "check flushing a nonexistent name ($n)" 170ret=0 171$RNDC $RNDCOPTS flushname fake.flushtest.example || ret=1 172if [ $ret != 0 ]; then echo_i "failed"; fi 173status=$((status + ret)) 174 175n=$((n + 1)) 176echo_i "check flushing of namespaces ($n)" 177ret=0 178clear_cache 179load_cache 180# flushing leaf node should leave the interior node: 181in_cache txt third1.second1.top1.flushtest.example || ret=1 182in_cache txt top1.flushtest.example || ret=1 183$RNDC $RNDCOPTS flushtree third1.second1.top1.flushtest.example 184in_cache txt third1.second1.top1.flushtest.example && ret=1 185in_cache txt top1.flushtest.example || ret=1 186in_cache txt second1.top1.flushtest.example || ret=1 187in_cache txt third2.second1.top1.flushtest.example || ret=1 188$RNDC $RNDCOPTS flushtree second1.top1.flushtest.example 189in_cache txt top1.flushtest.example || ret=1 190in_cache txt second1.top1.flushtest.example && ret=1 191in_cache txt third2.second1.top1.flushtest.example && ret=1 192 193# flushing from an empty node should still remove all its children 194in_cache txt second1.top2.flushtest.example || ret=1 195$RNDC $RNDCOPTS flushtree top2.flushtest.example 196in_cache txt second1.top2.flushtest.example && ret=1 197in_cache txt second2.top2.flushtest.example && ret=1 198in_cache txt second3.top2.flushtest.example && ret=1 199if [ $ret != 0 ]; then echo_i "failed"; fi 200status=$((status + ret)) 201 202n=$((n + 1)) 203echo_i "check flushing a nonexistent namespace ($n)" 204ret=0 205$RNDC $RNDCOPTS flushtree fake.flushtest.example || ret=1 206if [ $ret != 0 ]; then echo_i "failed"; fi 207status=$((status + ret)) 208 209n=$((n + 1)) 210echo_i "check the number of cached records remaining ($n)" 211ret=0 212dump_cache 213nrecords=$(filter_tree flushtest.example ns2/named_dump.db.test$n | grep -v '^;' | grep -E '(TXT|ANY)' | wc -l) 214[ $nrecords -eq 17 ] || { 215 ret=1 216 echo_i "found $nrecords records expected 17" 217} 218if [ $ret != 0 ]; then echo_i "failed"; fi 219status=$((status + ret)) 220 221n=$((n + 1)) 222echo_i "check the check that flushname of a partial match works ($n)" 223ret=0 224in_cache txt second2.top1.flushtest.example || ret=1 225$RNDC $RNDCOPTS flushtree example 226in_cache txt second2.top1.flushtest.example && ret=1 227if [ $ret != 0 ]; then echo_i "failed"; fi 228status=$((status + ret)) 229 230n=$((n + 1)) 231echo_i "check the number of cached records remaining ($n)" 232ret=0 233dump_cache 234nrecords=$(filter_tree flushtest.example ns2/named_dump.db.test$n | grep -E '(TXT|ANY)' | wc -l) 235[ $nrecords -eq 1 ] || { 236 ret=1 237 echo_i "found $nrecords records expected 1" 238} 239if [ $ret != 0 ]; then echo_i "failed"; fi 240status=$((status + ret)) 241 242n=$((n + 1)) 243echo_i "check flushtree clears adb correctly ($n)" 244ret=0 245load_cache 246dump_cache 247mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.a 248sed -n '/plain success\/timeout/,/Unassociated entries/p' \ 249 ns2/named_dump.db.test$n.a >sed.out.$n.a 250grep 'plain success/timeout' sed.out.$n.a >/dev/null 2>&1 || ret=1 251grep 'Unassociated entries' sed.out.$n.a >/dev/null 2>&1 || ret=1 252grep 'ns.flushtest.example' sed.out.$n.a >/dev/null 2>&1 || ret=1 253$RNDC $RNDCOPTS flushtree flushtest.example || ret=1 254dump_cache 255mv ns2/named_dump.db.test$n ns2/named_dump.db.test$n.b 256sed -n '/plain success\/timeout/,/Unassociated entries/p' \ 257 ns2/named_dump.db.test$n.b >sed.out.$n.b 258grep 'plain success/timeout' sed.out.$n.b >/dev/null 2>&1 || ret=1 259grep 'Unassociated entries' sed.out.$n.b >/dev/null 2>&1 || ret=1 260grep 'ns.flushtest.example' sed.out.$n.b >/dev/null 2>&1 && ret=1 261if [ $ret != 0 ]; then echo_i "failed"; fi 262status=$((status + ret)) 263 264n=$((n + 1)) 265echo_i "check expire option returned from primary zone ($n)" 266ret=0 267$DIG @10.53.0.1 -p ${PORT} +expire soa expire-test >dig.out.expire || ret=1 268grep EXPIRE: dig.out.expire >/dev/null || ret=1 269if [ $ret != 0 ]; then echo_i "failed"; fi 270status=$((status + ret)) 271 272n=$((n + 1)) 273echo_i "check expire option returned from secondary zone ($n)" 274ret=0 275$DIG @10.53.0.2 -p ${PORT} +expire soa expire-test >dig.out.expire || ret=1 276grep EXPIRE: dig.out.expire >/dev/null || ret=1 277if [ $ret != 0 ]; then echo_i "failed"; fi 278status=$((status + ret)) 279 280echo_i "exit status: $status" 281[ $status -eq 0 ] || exit 1 282