1# $NetBSD: t_ipsec_natt.sh,v 1.1 2017/10/30 15:59:23 ozaki-r 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 34 35DEBUG=${DEBUG:-false} 36HIJACKING_NPF="${HIJACKING},blanket=/dev/npf" 37 38setup_servers() 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_sp() 51{ 52 local proto=$1 53 local algo_args="$2" 54 local ip_local=$3 55 local ip_remote=$4 56 local ip_nat_remote=$5 57 local tmpfile=./tmp 58 59 export RUMP_SERVER=$SOCK_LOCAL 60 cat > $tmpfile <<-EOF 61 spdadd $ip_local $ip_remote any -P out ipsec $proto/transport//require; 62 spdadd $ip_remote $ip_local any -P in ipsec $proto/transport//require; 63 EOF 64 $DEBUG && cat $tmpfile 65 atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile 66 #check_sp_entries $SOCK_LOCAL $ip_local $ip_remote 67 68 export RUMP_SERVER=$SOCK_REMOTE 69 cat > $tmpfile <<-EOF 70 spdadd $ip_remote $ip_nat_remote any -P out ipsec $proto/transport//require; 71 spdadd $ip_local $ip_remote any -P in ipsec $proto/transport//require; 72 EOF 73 $DEBUG && cat $tmpfile 74 atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile 75 #check_sp_entries $SOCK_REMOTE $ip_remote $ip_local 76} 77 78add_sa() 79{ 80 local proto=$1 81 local algo_args="$2" 82 local ip_local=$3 83 local ip_remote=$4 84 local ip_nat_remote=$5 85 local spi=$6 86 local port=$7 87 local tmpfile=./tmp 88 89 export RUMP_SERVER=$SOCK_LOCAL 90 cat > $tmpfile <<-EOF 91 add $ip_local [4500] $ip_remote [4500] $proto $((spi)) $algo_args; 92 add $ip_remote [4500] $ip_local [4500] $proto $((spi + 1)) $algo_args; 93 EOF 94 $DEBUG && cat $tmpfile 95 atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile 96 $DEBUG && $HIJACKING setkey -D 97 # XXX it can be expired if $lifetime is very short 98 #check_sa_entries $SOCK_LOCAL $ip_local $ip_remote 99 100 export RUMP_SERVER=$SOCK_REMOTE 101 cat > $tmpfile <<-EOF 102 add $ip_local [$port] $ip_remote [4500] $proto $((spi)) $algo_args; 103 add $ip_remote [4500] $ip_nat_remote [$port] $proto $((spi + 1)) $algo_args; 104 EOF 105 $DEBUG && cat $tmpfile 106 atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile 107 $DEBUG && $HIJACKING setkey -D 108 # XXX it can be expired if $lifetime is very short 109 #check_sa_entries $SOCK_PEER $ip_local $ip_remote 110} 111 112prepare_file() 113{ 114 local file=$1 115 local data="0123456789" 116 117 touch $file 118 for i in `seq 1 512` 119 do 120 echo $data >> $file 121 done 122} 123 124build_npf_conf() 125{ 126 local outfile=$1 127 local localnet=$2 128 129 cat > $outfile <<-EOF 130 set bpf.jit off 131 \$int_if = inet4(shmif0) 132 \$ext_if = inet4(shmif1) 133 \$localnet = { $localnet } 134 map \$ext_if dynamic \$localnet -> \$ext_if 135 group "external" on \$ext_if { 136 pass stateful out final all 137 } 138 group "internal" on \$int_if { 139 block in all 140 pass in final from \$localnet 141 pass out final all 142 } 143 group default { 144 pass final on lo0 all 145 block all 146 } 147 EOF 148} 149 150PIDSFILE=./terminator.pids 151start_natt_terminator() 152{ 153 local sock=$1 154 local ip=$2 155 local port=$3 156 local pidsfile=$4 157 local backup=$RUMP_SERVER 158 local pid= 159 local terminator="$(atf_get_srcdir)/natt_terminator" 160 161 export RUMP_SERVER=$sock 162 163 env LD_PRELOAD=/usr/lib/librumphijack.so \ 164 $terminator $ip $port & 165 pid=$! 166 if [ ! -f $PIDSFILE ]; then 167 touch $PIDSFILE 168 fi 169 echo $pid >> $PIDSFILE 170 171 $DEBUG && rump.netstat -a -f inet 172 173 export RUMP_SERVER=$backup 174 175 sleep 1 176} 177 178stop_natt_terminators() 179{ 180 local pid= 181 182 if [ ! -f $PIDSFILE ]; then 183 return 184 fi 185 186 for pid in $(cat $PIDSFILE); do 187 kill -9 $pid 188 done 189 rm -f $PIDSFILE 190} 191 192test_ipsec_natt_transport() 193{ 194 local algo=$1 195 local ip_local=10.0.1.2 196 local ip_nat_local=10.0.1.1 197 local ip_nat_remote=20.0.0.1 198 local ip_remote=20.0.0.2 199 local subnet_local=10.0.1.0 200 local outfile=./out 201 local npffile=./npf.conf 202 local file_send=./file.send 203 local file_recv=./file.recv 204 local algo_args="$(generate_algo_args esp-udp $algo)" 205 local pid= port= 206 207 setup_servers 208 209 export RUMP_SERVER=$SOCK_LOCAL 210 atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0 211 atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24 212 atf_check -s exit:0 -o ignore \ 213 rump.route -n add default $ip_nat_local 214 215 export RUMP_SERVER=$SOCK_NAT 216 atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0 217 atf_check -s exit:0 rump.ifconfig shmif0 $ip_nat_local/24 218 atf_check -s exit:0 rump.ifconfig shmif1 $ip_nat_remote/24 219 atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=1 220 221 export RUMP_SERVER=$SOCK_REMOTE 222 atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0 223 atf_check -s exit:0 rump.ifconfig shmif0 $ip_remote/24 224 atf_check -s exit:0 -o ignore \ 225 rump.route -n add -net $subnet_local $ip_nat_remote 226 227 extract_new_packets $BUS_NAT > $outfile 228 229 # There is no NAT/NAPT. ping should just work. 230 export RUMP_SERVER=$SOCK_LOCAL 231 atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_remote 232 233 extract_new_packets $BUS_NAT > $outfile 234 $DEBUG && cat $outfile 235 atf_check -s exit:0 \ 236 -o match:"$ip_local > $ip_remote: ICMP echo request" \ 237 cat $outfile 238 atf_check -s exit:0 \ 239 -o match:"$ip_remote > $ip_local: ICMP echo reply" \ 240 cat $outfile 241 242 # Setup an NAPT with npf 243 build_npf_conf $npffile "$subnet_local/24" 244 245 export RUMP_SERVER=$SOCK_NAT 246 atf_check -s exit:0 $HIJACKING_NPF npfctl reload $npffile 247 atf_check -s exit:0 $HIJACKING_NPF npfctl start 248 $DEBUG && ${HIJACKING},"blanket=/dev/npf" npfctl show 249 250 # There is an NAPT. ping works but source IP/port are translated 251 export RUMP_SERVER=$SOCK_LOCAL 252 atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_remote 253 254 extract_new_packets $BUS_NAT > $outfile 255 $DEBUG && cat $outfile 256 atf_check -s exit:0 \ 257 -o match:"$ip_nat_remote > $ip_remote: ICMP echo request" \ 258 cat $outfile 259 atf_check -s exit:0 \ 260 -o match:"$ip_remote > $ip_nat_remote: ICMP echo reply" \ 261 cat $outfile 262 263 # Try TCP communications just in case 264 start_nc_server $SOCK_REMOTE 4501 $file_recv ipv4 265 prepare_file $file_send 266 export RUMP_SERVER=$SOCK_LOCAL 267 atf_check -s exit:0 $HIJACKING nc -w 3 $ip_remote 4501 < $file_send 268 atf_check -s exit:0 diff -q $file_send $file_recv 269 stop_nc_server 270 271 extract_new_packets $BUS_NAT > $outfile 272 $DEBUG && cat $outfile 273 atf_check -s exit:0 \ 274 -o match:"${ip_nat_remote}\.[0-9]+ > ${ip_remote}\.4501" \ 275 cat $outfile 276 atf_check -s exit:0 \ 277 -o match:"${ip_remote}\.4501 > ${ip_nat_remote}\.[0-9]+" \ 278 cat $outfile 279 280 # Launch a nc server as a terminator of NAT-T on outside the NAPT 281 start_natt_terminator $SOCK_REMOTE $ip_remote 4500 282 echo zzz > $file_send 283 284 export RUMP_SERVER=$SOCK_LOCAL 285 # Send a UDP packet to the remote server at port 4500 from the local 286 # host of port 4500. This makes a mapping on the NAPT between them 287 atf_check -s exit:0 $HIJACKING \ 288 nc -u -w 3 -p 4500 $ip_remote 4500 < $file_send 289 # Launch a nc server as a terminator of NAT-T on inside the NAPT, 290 # taking over port 4500 of the local host. 291 start_natt_terminator $SOCK_LOCAL $ip_local 4500 292 293 # We need to keep the servers for NAT-T 294 295 export RUMP_SERVER=$SOCK_LOCAL 296 $DEBUG && rump.netstat -na -f inet 297 export RUMP_SERVER=$SOCK_REMOTE 298 $DEBUG && rump.netstat -na -f inet 299 300 # Get a translated port number from 4500 on the NAPT 301 export RUMP_SERVER=$SOCK_NAT 302 $DEBUG && $HIJACKING_NPF npfctl list 303 # 10.0.1.2:4500 20.0.0.2:4500 via shmif1:9696 304 port=$($HIJACKING_NPF npfctl list | awk -F 'shmif1:' '/4500/ {print $2;}') 305 $DEBUG && echo port=$port 306 if [ -z "$port" ]; then 307 atf_fail "Failed to get a traslated port on NAPT" 308 fi 309 310 # Create ESP-UDP IPsec connections 311 setup_sp esp "$algo_args" $ip_local $ip_remote $ip_nat_remote 312 add_sa "esp-udp" "$algo_args" $ip_local $ip_remote $ip_nat_remote 10000 $port 313 314 # ping should still work 315 export RUMP_SERVER=$SOCK_LOCAL 316 atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_remote 317 318 # Try TCP communications over the ESP-UDP connections 319 start_nc_server $SOCK_REMOTE 4501 $file_recv ipv4 320 prepare_file $file_send 321 export RUMP_SERVER=$SOCK_LOCAL 322 atf_check -s exit:0 -o ignore $HIJACKING nc -w 3 $ip_remote 4501 < $file_send 323 atf_check -s exit:0 diff -q $file_send $file_recv 324 stop_nc_server 325 326 # Check both ports and UDP encapsulation 327 extract_new_packets $BUS_NAT > $outfile 328 $DEBUG && cat $outfile 329 atf_check -s exit:0 \ 330 -o match:"${ip_nat_remote}\.$port > ${ip_remote}\.4500: UDP-encap" \ 331 cat $outfile 332 atf_check -s exit:0 \ 333 -o match:"${ip_remote}\.4500 > ${ip_nat_remote}\.$port: UDP-encap" \ 334 cat $outfile 335 336 # Kill the NAT-T terminator 337 stop_natt_terminators 338} 339 340add_test_ipsec_natt_transport() 341{ 342 local algo=$1 343 local _algo=$(echo $algo | sed 's/-//g') 344 local name= desc= 345 346 desc="Test IPsec NAT-T ($algo)" 347 name="ipsec_natt_transport_${_algo}" 348 349 atf_test_case ${name} cleanup 350 eval " 351 ${name}_head() { 352 atf_set descr \"$desc\" 353 atf_set require.progs rump_server setkey nc 354 } 355 ${name}_body() { 356 test_ipsec_natt_transport $algo 357 rump_server_destroy_ifaces 358 } 359 ${name}_cleanup() { 360 stop_nc_server 361 stop_natt_terminators 362 \$DEBUG && dump 363 cleanup 364 } 365 " 366 atf_add_test_case ${name} 367} 368 369atf_init_test_cases() 370{ 371 local algo= 372 373 for algo in $ESP_ENCRYPTION_ALGORITHMS_MINIMUM; do 374 add_test_ipsec_natt_transport $algo 375 done 376} 377