t_ipsec_natt.sh revision 1.2.6.1 1 # $NetBSD: t_ipsec_natt.sh,v 1.2.6.1 2020/11/10 11:44:22 martin 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
28 SOCK_LOCAL_A=unix://ipsec_natt_local_a
29 SOCK_LOCAL_B=unix://ipsec_natt_local_b
30 SOCK_NAT=unix://ipsec_natt_nat
31 SOCK_REMOTE=unix://ipsec_natt_remote
32 BUS_LOCAL=./bus_ipsec_natt_local
33 BUS_NAT=./bus_ipsec_natt_nat
34
35 DEBUG=${DEBUG:-false}
36
37 setup_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
51 setup_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 atf_check -s exit:0 rump.ifconfig ipsec$ifid create
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
71 add_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
95 prepare_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
107 build_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
133 PIDSFILE=./terminator.pids
134 start_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
161 stop_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
175 check_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
199 check_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
227 check_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
260 check_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
295 test_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
488 add_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
517 atf_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