1#	$NetBSD: t_tunnel.sh,v 1.2 2020/08/29 07:22:49 tih Exp $
2#
3# Copyright (c) 2018 Ryota Ozaki <ozaki.ryota@gmail.com>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27
28BUS_LOCAL=bus_local
29BUS_TUN=bus_tun
30BUS_PEER=bus_peer
31SOCK_LOCAL=unix://wg_local
32SOCK_TUN_LOCAL=unix://wg_tun_local
33SOCK_TUN_PEER=unix://wg_tun_peer
34SOCK_PEER=unix://wg_peer
35
36escape_key()
37{
38
39	echo $1 | sed 's/\+/\\+/g' | sed 's|\/|\\/|g'
40}
41
42setup_servers()
43{
44
45	rump_server_start $SOCK_LOCAL netinet6
46	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS_LOCAL
47
48	rump_server_crypto_start $SOCK_TUN_LOCAL netinet6 wg
49	rump_server_add_iface $SOCK_TUN_LOCAL shmif0 $BUS_LOCAL
50	rump_server_add_iface $SOCK_TUN_LOCAL shmif1 $BUS_TUN
51
52	rump_server_crypto_start $SOCK_TUN_PEER netinet6 wg
53	rump_server_add_iface $SOCK_TUN_PEER shmif0 $BUS_PEER
54	rump_server_add_iface $SOCK_TUN_PEER shmif1 $BUS_TUN
55
56	rump_server_start $SOCK_PEER netinet6
57	rump_server_add_iface $SOCK_PEER shmif0 $BUS_PEER
58}
59
60setup_edge()
61{
62	local ifconfig="atf_check -s exit:0 rump.ifconfig"
63	local proto=$1
64	local ip=$2
65	local prefix=$3
66	local gw=$4
67	local ip_bad=$5
68	local alias=
69
70	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
71	atf_check -s exit:0 rump.sysctl -q -w net.inet6.ip6.dad_count=0
72	$ifconfig shmif0 $proto $ip/$prefix
73	atf_check -s exit:0 -o ignore rump.route add -$proto default $gw
74
75	if [ -z "$ip_bad" ]; then
76		return
77	fi
78
79	if [ $proto = inet ]; then
80		alias="alias"
81	fi
82
83	$ifconfig shmif0 $proto $ip_bad/$prefix $alias
84}
85
86setup_ip()
87{
88	local ifconfig="atf_check -s exit:0 rump.ifconfig"
89	local proto=$1
90	local ip=$2
91	local prefix=$3
92
93	$ifconfig shmif0 $proto $ip/$prefix
94}
95setup_router()
96{
97
98	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=1
99	atf_check -s exit:0 rump.sysctl -q -w net.inet6.ip6.forwarding=1
100	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
101	atf_check -s exit:0 rump.sysctl -q -w net.inet6.ip6.dad_count=0
102}
103
104setup_wg()
105{
106	local ifconfig="atf_check -s exit:0 rump.ifconfig"
107	local wgconfig="atf_check -s exit:0 $HIJACKING wgconfig"
108	local proto=$1
109	local ip=$2
110	local prefix=$3
111	local port=$4
112	local key_priv="$5"
113	local privfile=./tmp
114
115	$ifconfig wg0 create
116	$ifconfig wg0 $proto $ip/$prefix
117	$DEBUG && rump.netstat -nr
118	echo $key_priv > $privfile
119	$wgconfig wg0 set private-key $privfile
120	$wgconfig wg0 set listen-port $port
121	rm -f $privfile
122	$ifconfig wg0 up
123
124	check_conf_port wg0 $port
125	check_conf_privkey wg0 "$key_priv"
126}
127
128setup_wg_route()
129{
130	local proto=$1
131	local subnet=$2
132	local subnet_bad=$3
133
134	atf_check -s exit:0 -o ignore rump.route add -$proto -net $subnet -link wg0 -iface
135	if [ -n "$subnet_bad" ]; then
136		atf_check -s exit:0 -o ignore rump.route add -$proto -net $subnet_bad -link wg0 -iface
137	fi
138}
139
140prepare_file()
141{
142	local file=$1
143	local data="0123456789"
144
145	touch $file
146	for i in `seq 1 200`
147	do
148		echo $data >> $file
149	done
150}
151
152test_tcp()
153{
154	local proto=$1
155	local ip_peer=$2
156	local _proto=
157
158	prepare_file ./file_send
159
160	if [ $proto = inet ]; then
161		_proto=ipv4
162	else
163		_proto=ipv6
164	fi
165	start_nc_server $SOCK_PEER 1234 ./file_recv $_proto
166
167	export RUMP_SERVER=$SOCK_LOCAL
168	# Send a file to the server
169	# XXX Need a bit longer timeout value because the packet processing
170	# of the implementation is quite inefficient...
171	atf_check -s exit:0 $HIJACKING \
172	    nc -N -w 20 $ip_peer 1234 < ./file_send
173	$DEBUG && extract_new_packets $BUS > ./out
174	$DEBUG && cat ./out
175	stop_nc_server
176	$DEBUG && ls -s ./file_send ./file_recv
177	$DEBUG && wc -l ./file_send
178	$DEBUG && wc -l ./file_recv
179	$DEBUG && diff -u ./file_send ./file_recv
180	atf_check -s exit:0 diff -q ./file_send ./file_recv
181	rm -f ./out ./file_recv ./file_send
182}
183
184wg_tunnel_common()
185{
186	local outer_proto=$1
187	local inner_proto=$2
188	local ifconfig="atf_check -s exit:0 rump.ifconfig"
189	local wgconfig="atf_check -s exit:0 $HIJACKING wgconfig"
190	local port=51820
191	local ip_local= ip_peer=
192	local ip_wg_local= ip_wg_peer=
193	local outer_prefix= outer_prefixall=
194	local inner_prefix= inner_prefixall=
195
196	if [ $outer_proto = inet ]; then
197		ip_tun_local_tun=192.168.10.1
198		ip_tun_peer_tun=192.168.10.2
199		outer_prefix=24
200		outer_prefixall=32
201	else
202		ip_tun_local_tun=fc00:10::1
203		ip_tun_peer_tun=fc00:10::2
204		outer_prefix=64
205		outer_prefixall=128
206	fi
207
208	if [ $inner_proto = inet ]; then
209		ip_local=192.168.1.2
210		ip_tun_local=192.168.1.1
211		ip_wg_local=10.0.0.1
212		ip_wg_peer=10.0.0.2
213		ip_tun_peer=192.168.2.1
214		ip_peer=192.168.2.2
215		ip_peer_bad=192.168.3.2
216		inner_prefix=24
217		inner_prefixall=32
218		subnet_local=192.168.1.0/24
219		subnet_peer=192.168.2.0/24
220		subnet_peer_bad=192.168.3.0/24
221	else
222		ip_tun_local=fc00:1::1
223		ip_local=fc00:1::2
224		ip_wg_local=fd00::1
225		ip_wg_peer=fd00::2
226		ip_tun_peer=fc00:2::1
227		ip_peer=fc00:2::2
228		ip_peer_bad=fc00:3::2
229		inner_prefix=64
230		inner_prefixall=128
231		subnet_local=fc00:1::/64
232		subnet_peer=fc00:2::/64
233		subnet_peer_bad=fc00:3::/64
234	fi
235
236	setup_servers
237
238	# It sets key_priv_local key_pub_local key_priv_peer key_pub_peer
239	generate_keys
240
241	export RUMP_SERVER=$SOCK_LOCAL
242	setup_edge $inner_proto $ip_local $inner_prefix $ip_tun_local
243
244	export RUMP_SERVER=$SOCK_TUN_LOCAL
245	setup_router
246	$ifconfig shmif0 $inner_proto $ip_tun_local/$inner_prefix
247	$ifconfig shmif1 $outer_proto $ip_tun_local_tun/$outer_prefix
248	setup_wg $inner_proto $ip_wg_local $inner_prefix $port "$key_priv_local"
249	setup_wg_route $inner_proto $subnet_peer $subnet_peer_bad
250
251	export RUMP_SERVER=$SOCK_TUN_PEER
252	setup_router
253	$ifconfig shmif0 $inner_proto $ip_tun_peer/$inner_prefix
254	$ifconfig shmif1 $outer_proto $ip_tun_peer_tun/$outer_prefix
255	setup_wg $inner_proto $ip_wg_peer $inner_prefix $port "$key_priv_peer"
256	setup_wg_route $inner_proto $subnet_local
257
258	export RUMP_SERVER=$SOCK_PEER
259	setup_edge $inner_proto $ip_peer $inner_prefix $ip_tun_peer $ip_peer_bad
260
261	export RUMP_SERVER=$SOCK_TUN_LOCAL
262	add_peer wg0 peer0 $key_pub_peer $ip_tun_peer_tun:$port \
263	    $ip_wg_peer/$inner_prefixall,$subnet_peer
264
265	export RUMP_SERVER=$SOCK_TUN_PEER
266	add_peer wg0 peer0 $key_pub_local $ip_tun_local_tun:$port \
267	    $ip_wg_local/$inner_prefixall,$subnet_local
268
269	export RUMP_SERVER=$SOCK_TUN_LOCAL
270	atf_check -s exit:0 -o match:"latest-handshake: \(never\)" \
271	    $HIJACKING wgconfig wg0 show peer peer0
272
273	export RUMP_SERVER=$SOCK_LOCAL
274	check_ping $inner_proto $ip_peer
275
276	export RUMP_SERVER=$SOCK_TUN_LOCAL
277	atf_check -s exit:0 -o not-match:"latest-handshake: \(never\)" \
278	    $HIJACKING wgconfig wg0 show peer peer0
279
280	export RUMP_SERVER=$SOCK_LOCAL
281	# ping fails because the subnet of the IP is not allowed
282	check_ping_fail $inner_proto $ip_peer_bad
283
284	#
285	# Test TCP stream over the tunnel
286	#
287	test_tcp $inner_proto $ip_peer
288
289	export RUMP_SERVER=$SOCK_TUN_LOCAL
290	$ifconfig wg0 destroy
291	export RUMP_SERVER=$SOCK_TUN_PEER
292	$ifconfig wg0 destroy
293}
294
295add_tunnel_test()
296{
297	local inner=$1
298	local outer=$2
299	local ipv4=inet
300	local ipv6=inet6
301
302	name="wg_tunnel_${inner}_over_${outer}"
303	fulldesc="Test wg(4) with ${inner} over ${outer}"
304
305	eval inner=\$$inner
306	eval outer=\$$outer
307
308	atf_test_case ${name} cleanup
309	eval "
310		${name}_head() {
311			atf_set descr \"${fulldesc}\"
312			atf_set require.progs rump_server wgconfig wg-keygen
313		}
314		${name}_body() {
315			wg_tunnel_common $outer $inner
316			rump_server_destroy_ifaces
317		}
318		${name}_cleanup() {
319			\$DEBUG && dump
320			cleanup
321		}"
322	atf_add_test_case ${name}
323}
324
325atf_init_test_cases()
326{
327
328	add_tunnel_test ipv4 ipv4
329	add_tunnel_test ipv4 ipv6
330	add_tunnel_test ipv6 ipv4
331	add_tunnel_test ipv6 ipv6
332}
333