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