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
14# ns1 = stealth primary
15# ns2 = secondary with update forwarding disabled; not currently used
16# ns3 = secondary with update forwarding enabled
17
18set -e
19
20. ../conf.sh
21
22DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}"
23RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../_common/rndc.conf"
24
25status=0
26n=1
27capture_dnstap() {
28  retry_quiet 20 test -f ns3/dnstap.out && mv ns3/dnstap.out dnstap.out.$n
29  $RNDCCMD -s 10.53.0.3 dnstap -reopen
30}
31
32uq_equals_ur() {
33  "$DNSTAPREAD" dnstap.out.$n \
34    | awk '$3 == "UQ" { UQ+=1 } $3 == "UR" { UR += 1 } END { print UQ+0, UR+0 }' >dnstapread.out$n
35  read UQ UR <dnstapread.out$n
36  echo_i "UQ=$UQ UR=$UR"
37  test $UQ -eq $UR || return 1
38}
39
40echo_i "waiting for servers to be ready for testing ($n)"
41for i in 1 2 3 4 5 6 7 8 9 10; do
42  ret=0
43  $DIG +tcp -p ${PORT} example. @10.53.0.1 soa >dig.out.ns1 || ret=1
44  grep "status: NOERROR" dig.out.ns1 >/dev/null || ret=1
45  $DIG +tcp -p ${PORT} example. @10.53.0.2 soa >dig.out.ns2 || ret=1
46  grep "status: NOERROR" dig.out.ns2 >/dev/null || ret=1
47  $DIG +tcp -p ${PORT} example. @10.53.0.3 soa >dig.out.ns3 || ret=1
48  grep "status: NOERROR" dig.out.ns3 >/dev/null || ret=1
49  test $ret = 0 && break
50  sleep 1
51done
52if [ $ret != 0 ]; then
53  echo_i "failed"
54  status=$((status + ret))
55fi
56n=$((n + 1))
57
58echo_i "fetching primary copy of zone before update ($n)"
59ret=0
60$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1 || ret=1
61if [ $ret != 0 ]; then
62  echo_i "failed"
63  status=$((status + ret))
64fi
65n=$((n + 1))
66
67echo_i "fetching secondary 1 copy of zone before update ($n)"
68$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2 || ret=1
69if [ $ret != 0 ]; then
70  echo_i "failed"
71  status=$((status + ret))
72fi
73n=$((n + 1))
74
75echo_i "fetching secondary 2 copy of zone before update ($n)"
76ret=0
77$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3 || ret=1
78if [ $ret != 0 ]; then
79  echo_i "failed"
80  status=$((status + ret))
81fi
82n=$((n + 1))
83
84echo_i "comparing pre-update copies to known good data ($n)"
85ret=0
86digcomp knowngood.before dig.out.ns1 || ret=1
87digcomp knowngood.before dig.out.ns2 || ret=1
88digcomp knowngood.before dig.out.ns3 || ret=1
89if [ $ret != 0 ]; then
90  echo_i "failed"
91  status=$((status + ret))
92fi
93
94echo_i "updating zone (signed) ($n)"
95ret=0
96$NSUPDATE -y update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K -- - <<EOF || ret=1
97local 10.53.0.1
98server 10.53.0.3 ${PORT}
99update add updated.example. 600 A 10.10.10.1
100update add updated.example. 600 TXT Foo
101send
102EOF
103if [ $ret != 0 ]; then
104  echo_i "failed"
105  status=$((status + ret))
106fi
107n=$((n + 1))
108
109echo_i "sleeping 15 seconds for server to incorporate changes"
110sleep 15
111
112echo_i "fetching primary copy of zone after update ($n)"
113ret=0
114$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1 || ret=1
115if [ $ret != 0 ]; then
116  echo_i "failed"
117  status=$((status + ret))
118fi
119n=$((n + 1))
120
121echo_i "fetching secondary 1 copy of zone after update ($n)"
122ret=0
123$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2 || ret=1
124if [ $ret != 0 ]; then
125  echo_i "failed"
126  status=$((status + ret))
127fi
128
129echo_i "fetching secondary 2 copy of zone after update ($n)"
130ret=0
131$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3 || ret=1
132if [ $ret != 0 ]; then
133  echo_i "failed"
134  status=$((status + ret))
135fi
136n=$((n + 1))
137
138echo_i "comparing post-update copies to known good data ($n)"
139ret=0
140digcomp knowngood.after1 dig.out.ns1 || ret=1
141digcomp knowngood.after1 dig.out.ns2 || ret=1
142digcomp knowngood.after1 dig.out.ns3 || ret=1
143if [ $ret != 0 ]; then
144  echo_i "failed"
145  status=$((status + ret))
146fi
147
148echo_i "checking 'forwarding update for zone' is logged ($n)"
149ret=0
150grep "forwarding update for zone 'example/IN'" ns3/named.run >/dev/null || ret=1
151if [ $ret != 0 ]; then
152  echo_i "failed"
153  status=$((status + ret))
154fi
155n=$((n + 1))
156
157if $FEATURETEST --enable-dnstap; then
158  echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)"
159  ret=0
160  capture_dnstap
161  uq_equals_ur || ret=1
162  if [ $ret != 0 ]; then echo_i "failed"; fi
163  status=$((status + ret))
164  n=$((n + 1))
165fi
166
167echo_i "updating zone (unsigned) ($n)"
168ret=0
169$NSUPDATE -- - <<EOF || ret=1
170local 10.53.0.1
171server 10.53.0.3 ${PORT}
172update add unsigned.example. 600 A 10.10.10.1
173update add unsigned.example. 600 TXT Foo
174send
175EOF
176if [ $ret != 0 ]; then
177  echo_i "failed"
178  status=$((status + ret))
179fi
180n=$((n + 1))
181
182echo_i "sleeping 15 seconds for server to incorporate changes"
183sleep 15
184
185echo_i "fetching primary copy of zone after update ($n)"
186ret=0
187$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1 || ret=1
188if [ $ret != 0 ]; then
189  echo_i "failed"
190  status=$((status + ret))
191fi
192
193echo_i "fetching secondary 1 copy of zone after update ($n)"
194ret=0
195$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2 || ret=1
196if [ $ret != 0 ]; then
197  echo_i "failed"
198  status=$((status + ret))
199fi
200n=$((n + 1))
201
202echo_i "fetching secondary 2 copy of zone after update ($n)"
203ret=0
204$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3 || ret=1
205if [ $ret != 0 ]; then
206  echo_i "failed"
207  status=$((status + ret))
208fi
209
210echo_i "comparing post-update copies to known good data ($n)"
211ret=0
212digcomp knowngood.after2 dig.out.ns1 || ret=1
213digcomp knowngood.after2 dig.out.ns2 || ret=1
214digcomp knowngood.after2 dig.out.ns3 || ret=1
215if [ $ret != 0 ]; then
216  echo_i "failed"
217  status=$((status + ret))
218fi
219
220if $FEATURETEST --enable-dnstap; then
221  echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)"
222  ret=0
223  capture_dnstap
224  uq_equals_ur || ret=1
225  if [ $ret != 0 ]; then echo_i "failed"; fi
226  status=$((status + ret))
227  n=$((n + 1))
228fi
229n=$((n + 1))
230
231if test -f keyname; then
232  echo_i "checking update forwarding to with sig0 ($n)"
233  ret=0
234  keyname=$(cat keyname)
235  $NSUPDATE -k $keyname.private -- - <<EOF
236	local 10.53.0.1
237	server 10.53.0.3 ${PORT}
238	zone example2
239	update add unsigned.example2. 600 A 10.10.10.1
240	update add unsigned.example2. 600 TXT Foo
241	send
242EOF
243  $DIG -p ${PORT} unsigned.example2 A @10.53.0.1 >dig.out.ns1.test$n
244  grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
245  if [ $ret != 0 ]; then echo_i "failed"; fi
246  status=$((status + ret))
247  n=$((n + 1))
248
249  if $FEATURETEST --enable-dnstap; then
250    echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)"
251    ret=0
252    capture_dnstap
253    uq_equals_ur || ret=1
254    if [ $ret != 0 ]; then echo_i "failed"; fi
255    status=$((status + ret))
256    n=$((n + 1))
257  fi
258fi
259
260echo_i "attempting an update that should be rejected by ACL ($n)"
261ret=0
262{
263  $NSUPDATE -- - <<EOF
264        local 10.53.0.2
265        server 10.53.0.3 ${PORT}
266        update add another.unsigned.example. 600 A 10.10.10.2
267        update add another.unsigned.example. 600 TXT Bar
268        send
269EOF
270} >nsupdate.out.$n 2>&1 && ret=1
271grep REFUSED nsupdate.out.$n >/dev/null || ret=1
272if [ $ret != 0 ]; then
273  echo_i "failed"
274  status=$((status + ret))
275fi
276n=$((n + 1))
277
278echo_i "checking update forwarding to dead primary ($n)"
279count=0
280ret=0
281while [ $count -lt 5 -a $ret -eq 0 ]; do
282  (
283    $NSUPDATE -- - <<EOF
284local 10.53.0.1
285server 10.53.0.3 ${PORT}
286zone noprimary
287update add unsigned.noprimary. 600 A 10.10.10.1
288update add unsigned.noprimary. 600 TXT Foo
289send
290EOF
291  ) >/dev/null 2>&1 &
292  $DIG -p ${PORT} +noadd +notcp +noauth noprimary. @10.53.0.3 soa >dig.out.ns3 || ret=1
293  grep "status: NOERROR" dig.out.ns3 >/dev/null || ret=1
294  count=$((count + 1))
295done
296if [ $ret != 0 ]; then
297  echo_i "failed"
298  status=$((status + ret))
299fi
300n=$((n + 1))
301
302if $FEATURETEST --enable-dnstap; then
303  echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)"
304  ret=0
305  capture_dnstap
306  uq_equals_ur && ret=1
307  if [ $ret != 0 ]; then echo_i "failed"; fi
308  status=$((status + ret))
309  n=$((n + 1))
310fi
311
312n=$((n + 1))
313ret=0
314echo_i "attempting updates that should exceed quota ($n)"
315# lower the update quota to 1.
316copy_setports ns3/named2.conf.in ns3/named.conf
317rndc_reconfig ns3 10.53.0.3
318nextpart ns3/named.run >/dev/null
319for loop in 1 2 3 4 5 6 7 8 9 10; do
320  {
321    $NSUPDATE -- - >/dev/null 2>&1 <<END
322  local 10.53.0.1
323  server 10.53.0.3 ${PORT}
324  update add txt-$loop.unsigned.example 300 IN TXT Whatever
325  send
326END
327  } &
328done
329wait_for_log 10 "too many DNS UPDATEs queued" ns3/named.run || ret=1
330[ $ret = 0 ] || {
331  echo_i "failed"
332  status=1
333}
334
335echo_i "exit status: $status"
336[ $status -eq 0 ] || exit 1
337