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