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