Skip to content

Commit ec3d5e9

Browse files
committed
tests: move bulk data through a forward
scripts/fwd.test sends eight short lines, so nothing in the suite drives a forwarding channel past its first window, and a forward that stalled once the window needed crediting would go unnoticed. - push a payload several windows long through a local direct-tcpip forward and compare the bytes that arrive - give the listening nc its stdin from a fifo a sleep holds open: reading end-of-input makes nc close the connection, which truncates the transfer and looks exactly like a stall - bail out early once the byte count stops moving, so a real stall reports in seconds - read the size the receiver is held to back from the payload file - dump the logs on failure, check the listening nc came up, and take ports clear of the ones fwd.test.expect hardcodes, so a squatted or shared port is not reported as a stall
1 parent a47b9ab commit ec3d5e9

2 files changed

Lines changed: 198 additions & 0 deletions

File tree

scripts/fwd-bulk.test

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#!/bin/sh
2+
3+
# Bulk data through a local direct-tcpip forward.
4+
#
5+
# [nc client] --plain--> :$entry_port [portfwd]
6+
# |
7+
# SSH
8+
# |
9+
# [echoserver] --plain--> :$target_port [nc server]
10+
#
11+
# scripts/fwd.test moves a few hundred bytes, so nothing in the suite
12+
# exercises a forward past its first window. This pushes a payload several
13+
# windows long and compares the bytes that come out.
14+
#
15+
# The listening nc takes its stdin from a long sleep on purpose. Reading
16+
# end-of-input on stdin makes nc close the connection, which truncates the
17+
# transfer at whatever point the close lands and looks exactly like a
18+
# forwarding stall.
19+
20+
no_pid=-1
21+
hold_pid=$no_pid
22+
nc_server_pid=$no_pid
23+
server_pid=$no_pid
24+
portfwd_pid=$no_pid
25+
nc_client_pid=$no_pid
26+
work_dir="`pwd`/wolfssh_fwd_bulk$$"
27+
ready_file="$work_dir/ready"
28+
fwd_ready_file="$work_dir/fwd_ready"
29+
payload="$work_dir/payload"
30+
hold_fifo="$work_dir/hold"
31+
received="$work_dir/received"
32+
server_log="$work_dir/server.log"
33+
portfwd_log="$work_dir/portfwd.log"
34+
# Several times the 128K default window, so the transfer cannot finish
35+
# without the window being credited back at least once. The size the
36+
# receiver is held to is read back from the file dd made.
37+
payload_blocks=2000
38+
payload_size=0
39+
entry_port=0
40+
target_port=0
41+
port=0
42+
counter=0
43+
# Seconds to wait for the payload. Generous: the point is that a stalled
44+
# forward fails this test instead of hanging make check.
45+
transfer_limit=90
46+
# Consecutive seconds with no new bytes before calling it stalled.
47+
stall_limit=15
48+
49+
[ ! -x "`command -v nc`" ] && echo "nc doesn't exist, skipping" && exit 77
50+
[ ! -x ./examples/echoserver/echoserver ] \
51+
&& echo "echoserver doesn't exist, skipping" && exit 77
52+
./examples/echoserver/echoserver '-?' 2>&1 | grep -q "^echoserver " \
53+
|| { echo "echoserver doesn't run, skipping"; exit 77; }
54+
[ ! -x ./examples/portfwd/portfwd ] \
55+
&& echo "portfwd doesn't exist, skipping" && exit 77
56+
./examples/portfwd/portfwd '-?' 2>&1 | grep -q "does not exist" \
57+
&& { echo "forwarding not compiled in, skipping"; exit 77; }
58+
59+
# A WOLFSSH_TEST_BLOCK build fails writes at random, which stalls the
60+
# echoserver regardless of what the peer does. The other echoserver scripts
61+
# skip it for the same reason.
62+
WOLFSSH_OPTIONS=`./apps/wolfssh-options` || {
63+
echo "fail: could not run ./apps/wolfssh-options"
64+
exit 1
65+
}
66+
echo "$WOLFSSH_OPTIONS" | grep -qx "TEST_BLOCK" \
67+
&& { echo "macro WOLFSSH_TEST_BLOCK was used, skipping"; exit 77; }
68+
69+
do_cleanup() {
70+
for pid in $nc_client_pid $portfwd_pid $server_pid $nc_server_pid \
71+
$hold_pid
72+
do
73+
if [ "$pid" != "$no_pid" ]
74+
then
75+
kill -9 "$pid" 2>/dev/null
76+
wait "$pid" 2>/dev/null
77+
fi
78+
done
79+
rm -rf "$work_dir"
80+
}
81+
82+
# The failure here is usually just a byte count; the logs name the cause.
83+
do_dump_logs() {
84+
for log in "$server_log" "$portfwd_log"
85+
do
86+
echo "--- `basename "$log"` ---"
87+
cat "$log" 2>/dev/null
88+
done
89+
}
90+
91+
do_fail() {
92+
echo "$1"
93+
do_dump_logs
94+
do_cleanup
95+
exit 1
96+
}
97+
98+
do_trap() {
99+
echo "got trap"
100+
do_cleanup
101+
exit 1
102+
}
103+
104+
trap do_trap INT TERM
105+
106+
mkdir -p "$work_dir" || { echo "couldn't make the work directory"; exit 1; }
107+
108+
# portfwd and nc bind what they are told, so the plaintext ports have to be
109+
# picked here. Stamped with the pid so concurrent runs of the suite do not
110+
# collide, kept below the ephemeral range so an outgoing connection cannot
111+
# take one first, and clear of the ports fwd.test.expect hardcodes.
112+
entry_port=`expr 14000 + \( $$ % 1000 \)`
113+
target_port=`expr 15000 + \( $$ % 1000 \)`
114+
115+
dd if=/dev/urandom of="$payload" bs=1000 count=$payload_blocks 2>/dev/null \
116+
|| { echo "couldn't make the payload"; do_cleanup; exit 1; }
117+
payload_size=`wc -c < "$payload" | tr -d ' '`
118+
[ "$payload_size" -gt 0 ] \
119+
|| { echo "couldn't make the payload"; do_cleanup; exit 1; }
120+
121+
# nc closes the connection when it reads end-of-input on stdin, which
122+
# truncates the transfer. Hold stdin open with a sleep on the far side of a
123+
# fifo, so both ends have a pid this script can reap.
124+
mkfifo "$hold_fifo" || { echo "couldn't make the fifo"; do_cleanup; exit 1; }
125+
sleep 300 > "$hold_fifo" 2>/dev/null &
126+
hold_pid=$!
127+
nc -l $target_port < "$hold_fifo" > "$received" 2>/dev/null &
128+
nc_server_pid=$!
129+
130+
# A port already in use makes nc exit at once, and the echoserver's connect
131+
# would then be refused. Catch that here, or it reports as a stall.
132+
sleep 0.2
133+
if ! kill -0 "$nc_server_pid" 2>/dev/null
134+
then
135+
nc_server_pid=$no_pid
136+
echo "couldn't listen on port $target_port, is it in use?"
137+
do_cleanup
138+
exit 1
139+
fi
140+
141+
./examples/echoserver/echoserver -1 -f -R "$ready_file" \
142+
> "$server_log" 2>&1 &
143+
server_pid=$!
144+
145+
counter=0
146+
while [ ! -s "$ready_file" -a "$counter" -lt 20 ]; do
147+
sleep 0.1
148+
counter=`expr $counter + 1`
149+
done
150+
[ -s "$ready_file" ] || do_fail "no ready file, echoserver didn't start"
151+
port=`cat "$ready_file"`
152+
153+
./examples/portfwd/portfwd -u jill -P upthehill -p "$port" \
154+
-f $entry_port -t $target_port -R "$fwd_ready_file" \
155+
> "$portfwd_log" 2>&1 &
156+
portfwd_pid=$!
157+
158+
counter=0
159+
while [ ! -s "$fwd_ready_file" -a "$counter" -lt 20 ]; do
160+
sleep 0.1
161+
counter=`expr $counter + 1`
162+
done
163+
[ -s "$fwd_ready_file" ] || do_fail "no ready file, portfwd didn't start"
164+
165+
nc 127.0.0.1 $entry_port < "$payload" > /dev/null 2>&1 &
166+
nc_client_pid=$!
167+
168+
counter=0
169+
got=0
170+
last=0
171+
stalled=0
172+
while [ "$got" -lt "$payload_size" -a "$counter" -lt "$transfer_limit" ]; do
173+
sleep 1
174+
counter=`expr $counter + 1`
175+
got=`wc -c < "$received" 2>/dev/null | tr -d ' '`
176+
[ -z "$got" ] && got=0
177+
# Give up early once the byte count stops moving, so a stalled forward
178+
# reports in seconds instead of burning the whole limit.
179+
if [ "$got" -eq "$last" ]
180+
then
181+
stalled=`expr $stalled + 1`
182+
[ "$stalled" -ge "$stall_limit" ] && break
183+
else
184+
stalled=0
185+
last=$got
186+
fi
187+
done
188+
189+
[ "$got" -eq "$payload_size" ] \
190+
|| do_fail "forward stalled: sent $payload_size bytes, received $got"
191+
192+
cmp -s "$payload" "$received" \
193+
|| do_fail "forwarded data does not match what was sent"
194+
195+
echo "moved $payload_size bytes through a local forward"
196+
do_cleanup
197+
exit 0

scripts/include.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ dist_noinst_SCRIPTS+= scripts/sshclient.test
1717

1818
dist_noinst_SCRIPTS+= scripts/fwd.test
1919
EXTRA_DIST += scripts/fwd.test.expect
20+
dist_noinst_SCRIPTS+= scripts/fwd-bulk.test

0 commit comments

Comments
 (0)