xref: /netbsd-src/tests/net/if_ipsec/t_ipsec_natt.sh (revision f26b5d9d1135041c6205577ad6d4eb0c4ff8c173)
1#	$NetBSD: t_ipsec_natt.sh,v 1.5 2020/06/05 03:24:58 knakahara Exp $
2#
3# Copyright (c) 2018 Internet Initiative Japan Inc.
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
28SOCK_LOCAL_A=unix://ipsec_natt_local_a
29SOCK_LOCAL_B=unix://ipsec_natt_local_b
30SOCK_NAT=unix://ipsec_natt_nat
31SOCK_REMOTE=unix://ipsec_natt_remote
32BUS_LOCAL=./bus_ipsec_natt_local
33BUS_NAT=./bus_ipsec_natt_nat
34
35DEBUG=${DEBUG:-false}
36
37setup_servers()
38{
39
40	rump_server_crypto_start $SOCK_LOCAL_A netipsec ipsec
41	rump_server_crypto_start $SOCK_LOCAL_B netipsec ipsec
42	rump_server_npf_start $SOCK_NAT
43	rump_server_crypto_start $SOCK_REMOTE netipsec ipsec
44	rump_server_add_iface $SOCK_LOCAL_A shmif0 $BUS_LOCAL
45	rump_server_add_iface $SOCK_LOCAL_B shmif0 $BUS_LOCAL
46	rump_server_add_iface $SOCK_NAT shmif0 $BUS_LOCAL
47	rump_server_add_iface $SOCK_NAT shmif1 $BUS_NAT
48	rump_server_add_iface $SOCK_REMOTE shmif0 $BUS_NAT
49}
50
51setup_ipsecif()
52{
53	local sock=$1
54	local ifid=$2
55	local src_ip=$3
56	local src_port=$4
57	local dst_ip=$5
58	local dst_port=$6
59	local ipsecif_ip=$7
60	local peer_ip=$8
61
62	export RUMP_SERVER=$sock
63	rump_server_add_iface $sock ipsec$ifid
64	atf_check -s exit:0 rump.ifconfig ipsec$ifid link0 # enable NAT-T
65	atf_check -s exit:0 rump.ifconfig ipsec$ifid tunnel ${src_ip},${src_port} ${dst_ip},${dst_port}
66	atf_check -s exit:0 rump.ifconfig ipsec$ifid ${ipsecif_ip}/32
67	atf_check -s exit:0 -o ignore \
68	    rump.route -n add ${peer_ip}/32 $ipsecif_ip
69}
70
71add_sa()
72{
73	local sock=$1
74	local proto=$2
75	local algo_args="$3"
76	local src_ip=$4
77	local src_port=$5
78	local dst_ip=$6
79	local dst_port=$7
80	local out_spi=$8
81	local in_spi=$9
82	local tmpfile=./tmp
83
84	export RUMP_SERVER=$sock
85	cat > $tmpfile <<-EOF
86	add $src_ip [$src_port] $dst_ip [$dst_port] $proto $out_spi -m transport $algo_args;
87	add $dst_ip [$dst_port] $src_ip [$src_port] $proto $in_spi -m transport $algo_args;
88	EOF
89	$DEBUG && cat $tmpfile
90	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
91	# XXX it can be expired if $lifetime is very short
92	#check_sa_entries $SOCK_LOCAL $ip_local $ip_remote
93}
94
95prepare_file()
96{
97	local file=$1
98	local data="0123456789"
99
100	touch $file
101	for i in `seq 1 512`
102	do
103		echo $data >> $file
104	done
105}
106
107build_npf_conf()
108{
109	local outfile=$1
110	local localnet=$2
111
112	cat > $outfile <<-EOF
113	set bpf.jit off
114	\$int_if = inet4(shmif0)
115	\$ext_if = inet4(shmif1)
116	\$localnet = { $localnet }
117	map \$ext_if dynamic \$localnet -> \$ext_if
118	group "external" on \$ext_if {
119		pass stateful out final all
120	}
121	group "internal" on \$int_if {
122		block in all
123		pass in final from \$localnet
124		pass out final all
125	}
126	group default {
127		pass final on lo0 all
128		block all
129	}
130	EOF
131}
132
133PIDSFILE=./terminator.pids
134start_natt_terminator()
135{
136	local sock=$1
137	local ip=$2
138	local port=$3
139	local pidsfile=$4
140	local backup=$RUMP_SERVER
141	local pid=
142	local terminator="$(atf_get_srcdir)/../ipsec/natt_terminator"
143
144	export RUMP_SERVER=$sock
145
146	env LD_PRELOAD=/usr/lib/librumphijack.so \
147	    $terminator $ip $port &
148	pid=$!
149	if [ ! -f $PIDSFILE ]; then
150		touch $PIDSFILE
151	fi
152	echo $pid >> $PIDSFILE
153
154	$DEBUG && rump.netstat -a -f inet
155
156	export RUMP_SERVER=$backup
157
158	sleep 1
159}
160
161stop_natt_terminators()
162{
163	local pid=
164
165	if [ ! -f $PIDSFILE ]; then
166		return
167	fi
168
169	for pid in $(cat $PIDSFILE); do
170		kill -9 $pid
171	done
172	rm -f $PIDSFILE
173}
174
175check_ping_packets()
176{
177	local sock=$1
178	local bus=$2
179	local from_ip=$3
180	local to_ip=$4
181
182	local outfile=./out.ping
183
184	extract_new_packets $bus > $outfile
185
186	export RUMP_SERVER=$sock
187	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $to_ip
188
189	extract_new_packets $bus > $outfile
190	$DEBUG && cat $outfile
191	atf_check -s exit:0 \
192	    -o match:"$from_ip > $to_ip: ICMP echo request" \
193	    cat $outfile
194	atf_check -s exit:0 \
195	    -o match:"$to_ip > $from_ip: ICMP echo reply" \
196	    cat $outfile
197}
198
199check_ping_packets_over_ipsecif()
200{
201	local sock=$1
202	local bus=$2
203	local to_ip=$3
204	local nat_from_ip=$4
205	local nat_from_port=$5
206	local nat_to_ip=$6
207	local nat_to_port=$7
208
209	local outfile=./out.ping_over_ipsecif
210
211	extract_new_packets $bus > $outfile
212
213	export RUMP_SERVER=$sock
214	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 7 $to_ip
215
216	# Check both ports and UDP encapsulation
217	extract_new_packets $bus > $outfile
218	$DEBUG && cat $outfile
219	atf_check -s exit:0 \
220	    -o match:"${nat_from_ip}\.$nat_from_port > ${nat_to_ip}\.${nat_to_port}: UDP-encap" \
221	    cat $outfile
222	atf_check -s exit:0 \
223	    -o match:"${nat_to_ip}\.${nat_to_port} > ${nat_from_ip}\.${nat_from_port}: UDP-encap" \
224	    cat $outfile
225}
226
227check_tcp_com_prepare()
228{
229	local server_sock=$1
230	local client_sock=$2
231	local bus=$3
232	local to_ip=$4
233	local nat_from_ip=$5
234	local nat_to_ip=$6
235
236	local outfile=./out.prepare
237	local file_send=./file.send.prepare
238	local file_recv=./file.recv.prepare
239
240	extract_new_packets $bus > $outfile
241
242	start_nc_server $server_sock 4501 $file_recv ipv4
243
244	prepare_file $file_send
245	export RUMP_SERVER=$client_sock
246	atf_check -s exit:0 $HIJACKING nc -w 3 $to_ip 4501 < $file_send
247	atf_check -s exit:0 diff -q $file_send $file_recv
248	extract_new_packets $bus > $outfile
249	$DEBUG && cat $outfile
250	atf_check -s exit:0 \
251	    -o match:"${nat_from_ip}\.[0-9]+ > ${nat_to_ip}\.4501" \
252	    cat $outfile
253	atf_check -s exit:0 \
254	    -o match:"${nat_to_ip}\.4501 > ${nat_from_ip}\.[0-9]+" \
255	    cat $outfile
256
257	stop_nc_server
258}
259
260check_tcp_com_over_ipsecif()
261{
262	local server_sock=$1
263	local client_sock=$2
264	local bus=$3
265	local to_ip=$4
266	local nat_from_ip=$5
267	local nat_from_port=$6
268	local nat_to_ip=$7
269	local nat_to_port=$8
270
271	local outfile=./out.ipsecif
272	local file_send=./file.send.ipsecif
273	local file_recv=./file.recv.ipsecif
274
275	extract_new_packets $bus > $outfile
276
277	start_nc_server $server_sock 4501 $file_recv ipv4
278	prepare_file $file_send
279	export RUMP_SERVER=$client_sock
280	atf_check -s exit:0 -o ignore $HIJACKING nc -w 7 $to_ip 4501 < $file_send
281	atf_check -s exit:0 diff -q $file_send $file_recv
282	stop_nc_server
283
284	# Check both ports and UDP encapsulation
285	extract_new_packets $bus > $outfile
286	$DEBUG && cat $outfile
287	atf_check -s exit:0 \
288	    -o match:"${nat_from_ip}\.$nat_from_port > ${nat_to_ip}\.${nat_to_port}: UDP-encap" \
289	    cat $outfile
290	atf_check -s exit:0 \
291	    -o match:"${nat_to_ip}\.${nat_to_port} > ${nat_from_ip}\.${nat_from_port}: UDP-encap" \
292	    cat $outfile
293}
294
295test_ipsecif_natt_transport()
296{
297	local algo=$1
298	local ip_local_a=192.168.0.2
299	local ip_local_b=192.168.0.3
300	local ip_nat_local=192.168.0.1
301	local ip_nat_remote=10.0.0.1
302	local ip_remote=10.0.0.2
303	local subnet_local=192.168.0.0
304	local ip_local_ipsecif_a=172.16.100.1
305	local ip_local_ipsecif_b=172.16.110.1
306	local ip_remote_ipsecif_a=172.16.10.1
307	local ip_remote_ipsecif_b=172.16.11.1
308
309	local npffile=./npf.conf
310	local file_send=./file.send
311	local algo_args="$(generate_algo_args esp-udp $algo)"
312	local pid= port_a=  port_b=
313
314	setup_servers
315
316	export RUMP_SERVER=$SOCK_LOCAL_A
317	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
318	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local_a/24
319	atf_check -s exit:0 -o ignore \
320	    rump.route -n add default $ip_nat_local
321
322	export RUMP_SERVER=$SOCK_LOCAL_B
323	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
324	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local_b/24
325	atf_check -s exit:0 -o ignore \
326	    rump.route -n add default $ip_nat_local
327
328	export RUMP_SERVER=$SOCK_NAT
329	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
330	atf_check -s exit:0 rump.ifconfig shmif0 $ip_nat_local/24
331	atf_check -s exit:0 rump.ifconfig shmif1 $ip_nat_remote/24
332	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=1
333
334	export RUMP_SERVER=$SOCK_REMOTE
335	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
336	atf_check -s exit:0 rump.ifconfig shmif0 $ip_remote/24
337	atf_check -s exit:0 -o ignore \
338	    rump.route -n add -net $subnet_local $ip_nat_remote
339
340	# There is no NAT/NAPT. ping should just work.
341	check_ping_packets $SOCK_LOCAL_A $BUS_NAT $ip_local_a $ip_remote
342	check_ping_packets $SOCK_LOCAL_B $BUS_NAT $ip_local_b $ip_remote
343
344	# Setup an NAPT with npf
345	build_npf_conf $npffile "$subnet_local/24"
346
347	export RUMP_SERVER=$SOCK_NAT
348	atf_check -s exit:0 $HIJACKING_NPF npfctl reload $npffile
349	atf_check -s exit:0 $HIJACKING_NPF npfctl start
350	$DEBUG && ${HIJACKING},"blanket=/dev/npf" npfctl show
351
352	# There is an NAPT. ping works but source IP/port are translated
353	check_ping_packets $SOCK_LOCAL_A $BUS_NAT $ip_nat_remote $ip_remote
354	check_ping_packets $SOCK_LOCAL_B $BUS_NAT $ip_nat_remote $ip_remote
355
356	# Try TCP communications just in case
357	check_tcp_com_prepare $SOCK_REMOTE $SOCK_LOCAL_A $BUS_NAT \
358			      $ip_remote $ip_nat_remote $ip_remote
359	check_tcp_com_prepare $SOCK_REMOTE $SOCK_LOCAL_B $BUS_NAT \
360			      $ip_remote $ip_nat_remote $ip_remote
361
362	# Launch a nc server as a terminator of NAT-T on outside the NAPT
363	start_natt_terminator $SOCK_REMOTE $ip_remote 4500
364	echo zzz > $file_send
365
366	#################### Test for primary ipsecif(4) NAT-T.
367
368	export RUMP_SERVER=$SOCK_LOCAL_A
369	# Send a UDP packet to the remote server at port 4500 from the local
370	# host of port 4500. This makes a mapping on the NAPT between them
371	atf_check -s exit:0 $HIJACKING \
372	    nc -u -w 3 -p 4500 $ip_remote 4500 < $file_send
373	# Launch a nc server as a terminator of NAT-T on inside the NAPT,
374	# taking over port 4500 of the local host.
375	start_natt_terminator $SOCK_LOCAL_A $ip_local_a 4500
376
377	# We need to keep the servers for NAT-T
378
379	export RUMP_SERVER=$SOCK_LOCAL_A
380	$DEBUG && rump.netstat -na -f inet
381	export RUMP_SERVER=$SOCK_REMOTE
382	$DEBUG && rump.netstat -na -f inet
383
384	# Get a translated port number from 4500 on the NAPT
385	export RUMP_SERVER=$SOCK_NAT
386	$DEBUG && $HIJACKING_NPF npfctl list
387	#          192.168.0.2:4500 10.0.0.2:4500  via shmif1:65248
388	port_a=$(get_natt_port $ip_local_a $ip_nat_remote)
389	$DEBUG && echo port_a=$port_a
390	if [ -z "$port_a" ]; then
391		atf_fail "Failed to get a translated port on NAPT"
392	fi
393
394	# Setup ESP-UDP ipsecif(4) for first client under NAPT
395	setup_ipsecif $SOCK_LOCAL_A 0 $ip_local_a 4500 $ip_remote 4500 \
396		      $ip_local_ipsecif_a $ip_remote_ipsecif_a
397	setup_ipsecif $SOCK_REMOTE 0 $ip_remote 4500 $ip_nat_remote $port_a \
398		      $ip_remote_ipsecif_a $ip_local_ipsecif_a
399
400	add_sa $SOCK_LOCAL_A "esp-udp" "$algo_args" \
401	       $ip_local_a 4500 $ip_remote 4500 10000 10001
402	add_sa $SOCK_REMOTE "esp-udp" "$algo_args" \
403	       $ip_remote 4500 $ip_nat_remote $port_a 10001 10000
404
405	export RUMP_SERVER=$SOCK_LOCAL_A
406	# ping should still work
407	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_remote
408
409	# Try ping over the ESP-UDP ipsecif(4)
410	check_ping_packets_over_ipsecif $SOCK_LOCAL_A $BUS_NAT \
411					 $ip_remote_ipsecif_a $ip_nat_remote $port_a $ip_remote 4500
412
413	# Try TCP communications over the ESP-UDP ipsecif(4)
414	check_tcp_com_over_ipsecif $SOCK_REMOTE $SOCK_LOCAL_A $BUS_NAT \
415				   $ip_remote_ipsecif_a $ip_nat_remote $port_a $ip_remote 4500
416
417	#################### Test for secondary ipsecif(4) NAT-T.
418
419	export RUMP_SERVER=$SOCK_REMOTE
420	$HIJACKING setkey -D
421	$HIJACKING setkey -DP
422
423	export RUMP_SERVER=$SOCK_LOCAL_B
424	# Send a UDP packet to the remote server at port 4500 from the local
425	# host of port 4500. This makes a mapping on the NAPT between them
426	atf_check -s exit:0 $HIJACKING \
427	    nc -u -w 3 -p 4500 $ip_remote 4500 < $file_send
428	# Launch a nc server as a terminator of NAT-T on inside the NAPT,
429	# taking over port 4500 of the local host.
430	start_natt_terminator $SOCK_LOCAL_B $ip_local_b 4500
431
432	# We need to keep the servers for NAT-T
433
434	export RUMP_SERVER=$SOCK_LOCAL_B
435	$DEBUG && rump.netstat -na -f inet
436	export RUMP_SERVER=$SOCK_REMOTE
437	$DEBUG && rump.netstat -na -f inet
438
439	# Get a translated port number from 4500 on the NAPT
440	export RUMP_SERVER=$SOCK_NAT
441	$DEBUG && $HIJACKING_NPF npfctl list
442	#          192.168.0.2:4500 10.0.0.2:4500  via shmif1:65248
443	port_b=$(get_natt_port $ip_local_b $ip_nat_remote)
444	$DEBUG && echo port_b=$port_b
445	if [ -z "$port_b" ]; then
446		atf_fail "Failed to get a translated port on NAPT"
447	fi
448
449	# Setup ESP-UDP ipsecif(4) for first client under NAPT
450	setup_ipsecif $SOCK_LOCAL_B 0 $ip_local_b 4500 $ip_remote 4500 \
451		      $ip_local_ipsecif_b $ip_remote_ipsecif_b
452	setup_ipsecif $SOCK_REMOTE 1 $ip_remote 4500 $ip_nat_remote $port_b \
453		      $ip_remote_ipsecif_b $ip_local_ipsecif_b
454
455	check_ping_packets_over_ipsecif $SOCK_LOCAL_A $BUS_NAT \
456					 $ip_remote_ipsecif_a $ip_nat_remote $port_a $ip_remote 4500
457
458	add_sa $SOCK_LOCAL_B "esp-udp" "$algo_args" \
459	       $ip_local_b 4500 $ip_remote 4500 11000 11001
460	add_sa $SOCK_REMOTE "esp-udp" "$algo_args" \
461	       $ip_remote 4500 $ip_nat_remote $port_b 11001 11000
462
463	export RUMP_SERVER=$SOCK_LOCAL_B
464	# ping should still work
465	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_remote
466
467	# Try ping over the ESP-UDP ipsecif(4)
468	check_ping_packets_over_ipsecif $SOCK_LOCAL_B $BUS_NAT \
469					 $ip_remote_ipsecif_b $ip_nat_remote $port_b $ip_remote 4500
470
471
472	# Try TCP communications over the ESP-UDP ipsecif(4)
473	check_tcp_com_over_ipsecif $SOCK_REMOTE $SOCK_LOCAL_B $BUS_NAT \
474				   $ip_remote_ipsecif_b $ip_nat_remote $port_b $ip_remote 4500
475
476	# Try ping over the ESP-UDP ipsecif(4) for primary again
477	check_ping_packets_over_ipsecif $SOCK_LOCAL_A $BUS_NAT \
478					 $ip_remote_ipsecif_a $ip_nat_remote $port_a $ip_remote 4500
479
480	# Try TCP communications over the ESP-UDP ipsecif(4) for primary again
481	check_tcp_com_over_ipsecif $SOCK_REMOTE $SOCK_LOCAL_A $BUS_NAT \
482				   $ip_remote_ipsecif_a $ip_nat_remote $port_a $ip_remote 4500
483
484	# Kill the NAT-T terminator
485	stop_natt_terminators
486}
487
488add_test_ipsecif_natt_transport()
489{
490	local algo=$1
491	local _algo=$(echo $algo | sed 's/-//g')
492	local name= desc=
493
494	desc="Test ipsecif(4) NAT-T ($algo)"
495	name="ipsecif_natt_transport_${_algo}"
496
497	atf_test_case ${name} cleanup
498	eval "
499	    ${name}_head() {
500	        atf_set descr \"$desc\"
501	        atf_set require.progs rump_server setkey nc
502	    }
503	    ${name}_body() {
504	        test_ipsecif_natt_transport $algo
505	        rump_server_destroy_ifaces
506	    }
507	    ${name}_cleanup() {
508		stop_nc_server
509		stop_natt_terminators
510	        \$DEBUG && dump
511	        cleanup
512	    }
513	"
514	atf_add_test_case ${name}
515}
516
517atf_init_test_cases()
518{
519	local algo=
520
521	for algo in $ESP_ENCRYPTION_ALGORITHMS_MINIMUM; do
522		add_test_ipsecif_natt_transport $algo
523	done
524}
525