summaryrefslogtreecommitdiff
path: root/openvpn/tests/t_client.sh.in
blob: 6c9de6c337104f5032fb8af0891217f5d8e7f846 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#!@SHELL@
#
# run OpenVPN client against ``test reference'' server
# - check that ping, http, ... via tunnel works
# - check that interface config / routes are properly cleaned after test end
#
# prerequisites:
# - openvpn binary in current directory
# - writable current directory to create subdir for logs
# - t_client.rc in current directory OR source dir that specifies tests
# - for "ping4" checks: fping binary in $PATH
# - for "ping6" checks: fping6 binary in $PATH
#

srcdir="${srcdir:-.}"
top_builddir="${top_builddir:-..}"
if [ -r "${top_builddir}"/t_client.rc ] ; then
    . "${top_builddir}"/t_client.rc
elif [ -r "${srcdir}"/t_client.rc ] ; then
    . "${srcdir}"/t_client.rc
else
    echo "$0: cannot find 't_client.rc' in build dir ('${top_builddir}')" >&2
    echo "$0: or source directory ('${srcdir}'). SKIPPING TEST." >&2
    exit 77
fi

# Check for external dependencies
which fping > /dev/null
if [ $? -ne 0 ]; then
    echo "$0: fping is not available in \$PATH" >&2
    exit 77
fi
which fping6 > /dev/null
if [ $? -ne 0 ]; then
    echo "$0: fping6 is not available in \$PATH" >&2
    exit 77
fi

if [ ! -x "${top_builddir}/src/openvpn/openvpn" ]
then
    echo "no (executable) openvpn binary in current build tree. FAIL." >&2
    exit 1
fi

if [ ! -w . ]
then
    echo "current directory is not writable (required for logging). FAIL." >&2
    exit 1
fi

if [ -z "$CA_CERT" ] ; then
    echo "CA_CERT not defined in 't_client.rc'. SKIP test." >&2
    exit 77
fi

if [ -z "$TEST_RUN_LIST" ] ; then
    echo "TEST_RUN_LIST empty, no tests defined.  SKIP test." >&2
    exit 77
fi

# make sure we have permissions to run ifconfig/route from OpenVPN
# can't use "id -u" here - doesn't work on Solaris
ID=`id`
if expr "$ID" : "uid=0" >/dev/null
then :
else
    if [ -z "$RUN_SUDO" ]
    then
        echo "$0: this test must run be as root, or RUN_SUDO=... " >&2
        echo "      must be set correctly in 't_client.rc'. SKIP." >&2
        exit 77
    fi
fi

LOGDIR=t_client-`hostname`-`date +%Y%m%d-%H%M%S`
if mkdir $LOGDIR
then :
else
    echo "can't create log directory '$LOGDIR'. FAIL." >&2
    exit 1
fi

exit_code=0

# ----------------------------------------------------------
# helper functions
# ----------------------------------------------------------
# print failure message, increase FAIL counter
fail()
{
    echo ""
    echo "FAIL: $@" >&2
    fail_count=$(( $fail_count + 1 ))
}

# print "all interface IP addresses" + "all routes"
# this is higly system dependent...
get_ifconfig_route()
{
    # linux / iproute2? (-> if configure got a path)
    if [ -n "@IPROUTE@" ]
    then
	echo "-- linux iproute2 --"
	@IPROUTE@ addr show     | grep -v valid_lft
	@IPROUTE@ route show
	@IPROUTE@ -o -6 route show | grep -v ' cache' | sed -E -e 's/ expires [0-9]*sec//' -e 's/ (mtu|hoplimit|cwnd) [0-9]+//g' -e 's/ (rtt|rttvar) [0-9]+ms//g'
	return
    fi

    # try uname
    case `uname -s` in
	Linux)
	   echo "-- linux / ifconfig --"
	   LANG=C @IFCONFIG@ -a |egrep  "( addr:|encap:)"
	   LANG=C @NETSTAT@ -rn -4 -6
	   return
	   ;;
	FreeBSD|NetBSD|Darwin)
	   echo "-- FreeBSD/NetBSD/Darwin [MacOS X] --"
	   @IFCONFIG@ -a | egrep "(flags=|inet)"
	   @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$NF }'
	   return
	   ;;
	OpenBSD)
	   echo "-- OpenBSD --"
	   @IFCONFIG@ -a | egrep "(flags=|inet)" | \
		sed -e 's/pltime [0-9]*//' -e 's/vltime [0-9]*//'
	   @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$NF }'
	   return
	   ;;
	SunOS)
	   echo "-- Solaris --"
	   @IFCONFIG@ -a | egrep "(flags=|inet)"
	   @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$6 }'
	   return
	   ;;
    esac

    echo "get_ifconfig_route(): no idea how to get info on your OS.  FAIL." >&2
    exit 20
}

# ----------------------------------------------------------
# check ifconfig
#  arg1: "4" or "6" -> for message
#  arg2: IPv4/IPv6 address that must show up in out of "get_ifconfig_route"
check_ifconfig()
{
    proto=$1 ; shift
    expect_list="$@"

    if [ -z "$expect_list" ] ; then return ; fi

    for expect in $expect_list
    do
	if get_ifconfig_route | fgrep "$expect" >/dev/null
	then :
	else
	    fail "check_ifconfig(): expected IPv$proto address '$expect' not found in ifconfig output."
	fi
    done
}

# ----------------------------------------------------------
# run pings
#  arg1: "4" or "6" -> fping/fing6
#  arg2: "want_ok" or "want_fail" (expected ping result)
#  arg3... -> fping arguments (host list)
run_ping_tests()
{
    proto=$1 ; want=$2 ; shift ; shift
    targetlist="$@"

    # "no targets" is fine
    if [ -z "$targetlist" ] ; then return ; fi

    case $proto in
	4) cmd=fping ;;
	6) cmd=fping6 ;;
	*) echo "internal error in run_ping_tests arg 1: '$proto'" >&2
	   exit 1 ;;
    esac

    case $want in
	want_ok)   sizes_list="64 1440 3000" ;;
	want_fail) sizes_list="64" ;;
    esac

    for bytes in $sizes_list
    do
	echo "run IPv$proto ping tests ($want), $bytes byte packets..."

	echo "$cmd -b $bytes -C 20 -p 250 -q $targetlist" >>$LOGDIR/$SUF:fping.out
	$cmd -b $bytes -C 20 -p 250 -q $targetlist >>$LOGDIR/$SUF:fping.out 2>&1

	# while OpenVPN is running, pings must succeed (want='want_ok')
	# before OpenVPN is up, pings must NOT succeed (want='want_fail')

	rc=$?
	if [ $rc = 0 ] 				# all ping OK
	then
	    if [ $want = "want_fail" ]		# not what we want
	    then
		fail "IPv$proto ping test succeeded, but needs to *fail*."
	    fi
	else					# ping failed
	    if [ $want = "want_ok" ]		# not what we wanted
	    then
		fail "IPv$proto ping test ($bytes bytes) failed, but should succeed."
	    fi
	fi
    done
}

# ----------------------------------------------------------
# main test loop
# ----------------------------------------------------------
SUMMARY_OK=
SUMMARY_FAIL=

for SUF in $TEST_RUN_LIST
do
    # get config variables
    eval test_prep=\"\$PREPARE_$SUF\"
    eval test_cleanup=\"\$CLEANUP_$SUF\"
    eval test_run_title=\"\$RUN_TITLE_$SUF\"
    eval openvpn_conf=\"\$OPENVPN_CONF_$SUF\"
    eval expect_ifconfig4=\"\$EXPECT_IFCONFIG4_$SUF\"
    eval expect_ifconfig6=\"\$EXPECT_IFCONFIG6_$SUF\"
    eval ping4_hosts=\"\$PING4_HOSTS_$SUF\"
    eval ping6_hosts=\"\$PING6_HOSTS_$SUF\"

    echo -e "\n### test run $SUF: '$test_run_title' ###\n"
    fail_count=0

    if [ -n "$test_prep" ]; then
        echo -e "running preparation: '$test_prep'"
        eval $test_prep
    fi

    echo "save pre-openvpn ifconfig + route"
    get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route_pre.txt

    echo -e "\nrun pre-openvpn ping tests - targets must not be reachable..."
    run_ping_tests 4 want_fail "$ping4_hosts"
    run_ping_tests 6 want_fail "$ping6_hosts"
    if [ "$fail_count" = 0 ] ; then
        echo -e "OK.\n"
    else
	echo -e "FAIL: make sure that ping hosts are ONLY reachable via VPN, SKIP test $SUF".
	exit_code=31
	continue
    fi

    echo " run openvpn $openvpn_conf"
    echo "# src/openvpn/openvpn $openvpn_conf" >$LOGDIR/$SUF:openvpn.log
    $RUN_SUDO "${top_builddir}/src/openvpn/openvpn" $openvpn_conf >>$LOGDIR/$SUF:openvpn.log &
    opid=$!

    # make sure openvpn client is terminated in case shell exits
    trap "$RUN_SUDO kill $opid" 0
    trap "$RUN_SUDO kill $opid ; trap - 0 ; exit 1" 1 2 3 15

    echo "wait for connection to establish..."
    sleep ${SETUP_TIME_WAIT:-10}

    # test whether OpenVPN process is still there
    if $RUN_SUDO kill -0 $opid
    then :
    else
	echo -e "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log).  FAIL.\ntail of logfile follows:\n..." >&2
	tail $LOGDIR/$SUF:openvpn.log >&2
	trap - 0 1 2 3 15
	exit 10
    fi

    # compare whether anything changed in ifconfig/route setup?
    echo "save ifconfig+route"
    get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route.txt

    echo -n "compare pre-openvpn ifconfig+route with current values..."
    if diff $LOGDIR/$SUF:ifconfig_route_pre.txt \
	    $LOGDIR/$SUF:ifconfig_route.txt >/dev/null
    then
	fail "no differences between ifconfig/route before OpenVPN start and now."
    else
	echo -e " OK!\n"
    fi

    # expected ifconfig values in there?
    check_ifconfig 4 "$expect_ifconfig4"
    check_ifconfig 6 "$expect_ifconfig6"

    run_ping_tests 4 want_ok "$ping4_hosts"
    run_ping_tests 6 want_ok "$ping6_hosts"
    echo -e "ping tests done.\n"

    echo "stopping OpenVPN"
    $RUN_SUDO kill $opid
    wait $!
    rc=$?
    if [ $rc != 0 ] ; then
	fail "OpenVPN return code $rc, expect 0"
    fi

    echo -e "\nsave post-openvpn ifconfig + route..."
    get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route_post.txt

    echo -n "compare pre- and post-openvpn ifconfig + route..."
    if diff $LOGDIR/$SUF:ifconfig_route_pre.txt \
	    $LOGDIR/$SUF:ifconfig_route_post.txt >$LOGDIR/$SUF:ifconfig_route_diff.txt
    then
	echo -e " OK.\n"
    else
	cat $LOGDIR/$SUF:ifconfig_route_diff.txt >&2
	fail "differences between pre- and post-ifconfig/route"
    fi
    if [ "$fail_count" = 0 ] ; then
        echo -e "test run $SUF: all tests OK.\n"
	SUMMARY_OK="$SUMMARY_OK $SUF"
    else
	echo -e "test run $SUF: $fail_count test failures. FAIL.\n";
	SUMMARY_FAIL="$SUMMARY_FAIL $SUF"
	exit_code=30
    fi

    if [ -n "$test_cleanup" ]; then
        echo -e "cleaning up: '$test_cleanup'"
        eval $test_cleanup
    fi

done

if [ -z "$SUMMARY_OK" ] ; then SUMMARY_OK=" none"; fi
if [ -z "$SUMMARY_FAIL" ] ; then SUMMARY_FAIL=" none"; fi
echo "Test sets succeded:$SUMMARY_OK."
echo "Test sets failed:$SUMMARY_FAIL."

# remove trap handler
trap - 0 1 2 3 15
exit $exit_code