xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/tcp/tests.sh (revision 8aaca124c0ad52af9550477f296b63debc7b4c98)
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# shellcheck source=../conf.sh
17. ../conf.sh
18
19dig_with_opts() {
20  "${DIG}" -p "${PORT}" "$@"
21}
22
23rndccmd() {
24  "${RNDC}" -p "${CONTROLPORT}" -c ../_common/rndc.conf -s "$@"
25}
26
27status=0
28n=0
29
30n=$((n + 1))
31echo_i "initializing TCP statistics ($n)"
32ret=0
33rndccmd 10.53.0.1 stats || ret=1
34rndccmd 10.53.0.2 stats || ret=1
35mv ns1/named.stats ns1/named.stats.test$n
36mv ns2/named.stats ns2/named.stats.test$n
37ntcp10="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')"
38ntcp20="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')"
39if [ $ret != 0 ]; then echo_i "failed"; fi
40status=$((status + ret))
41
42n=$((n + 1))
43echo_i "checking TCP request statistics (resolver) ($n)"
44ret=0
45dig_with_opts @10.53.0.3 txt.example. >dig.out.test$n
46sleep 1
47rndccmd 10.53.0.1 stats || ret=1
48rndccmd 10.53.0.2 stats || ret=1
49mv ns1/named.stats ns1/named.stats.test$n
50mv ns2/named.stats ns2/named.stats.test$n
51ntcp11="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')"
52ntcp21="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')"
53if [ "$ntcp10" -ge "$ntcp11" ]; then ret=1; fi
54if [ "$ntcp20" -ne "$ntcp21" ]; then ret=1; fi
55if [ $ret != 0 ]; then echo_i "failed"; fi
56status=$((status + ret))
57
58n=$((n + 1))
59echo_i "checking TCP request statistics (forwarder) ($n)"
60ret=0
61dig_with_opts @10.53.0.4 txt.example. >dig.out.test$n
62sleep 1
63rndccmd 10.53.0.1 stats || ret=1
64rndccmd 10.53.0.2 stats || ret=1
65mv ns1/named.stats ns1/named.stats.test$n
66mv ns2/named.stats ns2/named.stats.test$n
67ntcp12="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')"
68ntcp22="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')"
69if [ "$ntcp11" -ne "$ntcp12" ]; then ret=1; fi
70if [ "$ntcp21" -ge "$ntcp22" ]; then ret=1; fi
71if [ $ret != 0 ]; then echo_i "failed"; fi
72status=$((status + ret))
73
74# -------- TCP high-water tests ----------
75refresh_tcp_stats() {
76  rndccmd 10.53.0.5 status >rndc.out.$n || ret=1
77  TCP_CUR="$(sed -n "s/^tcp clients: \([0-9][0-9]*\).*/\1/p" rndc.out.$n)"
78  TCP_LIMIT="$(sed -n "s/^tcp clients: .*\/\([0-9][0-9]*\)/\1/p" rndc.out.$n)"
79  TCP_HIGH="$(sed -n "s/^TCP high-water: \([0-9][0-9]*\)/\1/p" rndc.out.$n)"
80}
81
82# Send a command to the tool script listening on 10.53.0.6.
83send_command() {
84  nextpart ans6/ans.run >/dev/null
85  echo "$*" | send 10.53.0.6 "${CONTROLPORT}"
86  wait_for_log_peek 10 "result=" ans6/ans.run || ret=1
87  if ! nextpartpeek ans6/ans.run | grep -qF "result=OK"; then
88    return 1
89  fi
90}
91
92# Instructs ans6 to open $1 TCP connections to 10.53.0.5.
93open_connections() {
94  send_command "open" "${1}" 10.53.0.5 "${PORT}" || return 1
95}
96
97# Instructs ans6 to close $1 TCP connections to 10.53.0.5.
98close_connections() {
99  send_command "close" "${1}" || return 1
100}
101
102# Check TCP connections are working normally before opening
103# multiple connections
104n=$((n + 1))
105echo_i "checking TCP query repsonse ($n)"
106ret=0
107dig_with_opts +tcp @10.53.0.5 txt.example >dig.out.test$n
108grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
109if [ $ret != 0 ]; then echo_i "failed"; fi
110status=$((status + ret))
111
112# Check TCP statistics after server startup before using them as a baseline for
113# subsequent checks.
114n=$((n + 1))
115echo_i "TCP high-water: check initial statistics ($n)"
116ret=0
117refresh_tcp_stats
118assert_int_equal "${TCP_CUR}" 0 "current TCP clients count" || ret=1
119# We compare initial tcp-highwater value with 1 because as part of the
120# system test startup, the script start.pl executes dig to check if target
121# named is running, and that increments tcp-quota by one.
122assert_int_equal "${TCP_HIGH}" 1 "tcp-highwater count" || ret=1
123if [ $ret != 0 ]; then echo_i "failed"; fi
124status=$((status + ret))
125
126# Ensure the TCP high-water statistic gets updated after some TCP connections
127# are established.
128n=$((n + 1))
129echo_i "TCP high-water: check value after some TCP connections are established ($n)"
130ret=0
131OLD_TCP_CUR="${TCP_CUR}"
132TCP_ADDED=9
133open_connections "${TCP_ADDED}" || ret=1
134check_stats_added() {
135  refresh_tcp_stats
136  assert_int_equal "${TCP_CUR}" $((OLD_TCP_CUR + TCP_ADDED)) "current TCP clients count" || return 1
137  assert_int_equal "${TCP_HIGH}" $((OLD_TCP_CUR + TCP_ADDED)) "TCP high-water value" || return 1
138}
139retry 2 check_stats_added || ret=1
140if [ $ret != 0 ]; then echo_i "failed"; fi
141status=$((status + ret))
142
143# Ensure the TCP high-water statistic remains unchanged after some TCP
144# connections are closed.
145n=$((n + 1))
146echo_i "TCP high-water: check value after some TCP connections are closed ($n)"
147ret=0
148OLD_TCP_CUR="${TCP_CUR}"
149OLD_TCP_HIGH="${TCP_HIGH}"
150TCP_REMOVED=5
151close_connections "${TCP_REMOVED}" || ret=1
152check_stats_removed() {
153  refresh_tcp_stats
154  assert_int_equal "${TCP_CUR}" $((OLD_TCP_CUR - TCP_REMOVED)) "current TCP clients count" || return 1
155  assert_int_equal "${TCP_HIGH}" "${OLD_TCP_HIGH}" "TCP high-water value" || return 1
156}
157retry 2 check_stats_removed || ret=1
158if [ $ret != 0 ]; then echo_i "failed"; fi
159status=$((status + ret))
160
161# Ensure the TCP high-water statistic never exceeds the configured TCP clients
162# limit.
163n=$((n + 1))
164echo_i "TCP high-water: ensure tcp-clients is an upper bound ($n)"
165ret=0
166open_connections $((TCP_LIMIT + 1)) || ret=1
167check_stats_limit() {
168  refresh_tcp_stats
169  assert_int_equal "${TCP_CUR}" "${TCP_LIMIT}" "current TCP clients count" || return 1
170  assert_int_equal "${TCP_HIGH}" "${TCP_LIMIT}" "TCP high-water value" || return 1
171}
172retry 2 check_stats_limit || ret=1
173if [ $ret != 0 ]; then echo_i "failed"; fi
174status=$((status + ret))
175
176# Check TCP connections are working normally before opening
177# multiple connections
178n=$((n + 1))
179echo_i "checking TCP response recovery ($n)"
180ret=0
181# "0" closes all connections
182close_connections 0 || ret=1
183dig_with_opts +tcp @10.53.0.5 txt.example >dig.out.test$n || ret=1
184grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
185if [ $ret != 0 ]; then echo_i "failed"; fi
186status=$((status + ret))
187
188####################################################
189# NOTE: The next test resets the debug level to 1. #
190####################################################
191
192n=$((n + 1))
193echo_i "checking that BIND 9 doesn't crash on long TCP messages ($n)"
194ret=0
195# Avoid logging useless information.
196rndccmd 10.53.0.1 trace 1 || ret=1
197{ $PERL ../packet.pl -a "10.53.0.1" -p "${PORT}" -t tcp -r 300000 1996-alloc_dnsbuf-crash-test.pkt || ret=1; } | cat_i
198dig_with_opts +tcp @10.53.0.1 txt.example >dig.out.test$n || ret=1
199if [ $ret != 0 ]; then echo_i "failed"; fi
200status=$((status + ret))
201
202echo_i "exit status: $status"
203[ $status -eq 0 ] || exit 1
204