Home | History | Annotate | Line # | Download | only in ipsec
t_ipsec_misc.sh revision 1.23
      1 #	$NetBSD: t_ipsec_misc.sh,v 1.23 2019/07/23 04:31:25 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 
     28 SOCK_LOCAL=unix://ipsec_local
     29 SOCK_PEER=unix://ipsec_peer
     30 BUS=./bus_ipsec
     31 
     32 DEBUG=${DEBUG:-true}
     33 
     34 setup_sasp()
     35 {
     36 	local proto=$1
     37 	local algo_args="$2"
     38 	local ip_local=$3
     39 	local ip_peer=$4
     40 	local lifetime=$5
     41 	local update=$6
     42 	local tmpfile=./tmp
     43 	local saadd=add
     44 	local saadd_algo_args="$algo_args"
     45 	local extra=
     46 
     47 	if [ "$update" = getspi ]; then
     48 		saadd=getspi
     49 		saadd_algo_args=
     50 	fi
     51 
     52 	if [ "$update" = sa -o "$update" = getspi ]; then
     53 		extra="update $ip_local $ip_peer $proto 10000 $algo_args;
     54 		       update $ip_peer $ip_local $proto 10001 $algo_args;"
     55 	elif [ "$update" = sp ]; then
     56 		extra="spdupdate $ip_local $ip_peer any -P out ipsec $proto/transport//require;"
     57 	fi
     58 
     59 	export RUMP_SERVER=$SOCK_LOCAL
     60 	cat > $tmpfile <<-EOF
     61 	$saadd $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $saadd_algo_args;
     62 	$saadd $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $saadd_algo_args;
     63 	spdadd $ip_local $ip_peer any -P out ipsec $proto/transport//require;
     64 	$extra
     65 	EOF
     66 	$DEBUG && cat $tmpfile
     67 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
     68 	# XXX it can be expired if $lifetime is very short
     69 	#check_sa_entries $SOCK_LOCAL $ip_local $ip_peer
     70 
     71 	if [ "$update" = sp ]; then
     72 		extra="spdupdate $ip_peer $ip_local any -P out ipsec $proto/transport//require;"
     73 	fi
     74 
     75 	export RUMP_SERVER=$SOCK_PEER
     76 	cat > $tmpfile <<-EOF
     77 	$saadd $ip_local $ip_peer $proto 10000 -lh $lifetime -ls $lifetime $saadd_algo_args;
     78 	$saadd $ip_peer $ip_local $proto 10001 -lh $lifetime -ls $lifetime $saadd_algo_args;
     79 	spdadd $ip_peer $ip_local any -P out ipsec $proto/transport//require;
     80 	$extra
     81 	EOF
     82 	$DEBUG && cat $tmpfile
     83 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
     84 	# XXX it can be expired if $lifetime is very short
     85 	#check_sa_entries $SOCK_PEER $ip_local $ip_peer
     86 }
     87 
     88 test_sad_disapper_until()
     89 {
     90 	local time=$1
     91 	local check_dead_sa=$2
     92 	local setkey_opts=
     93 	local n=$time
     94 	local tmpfile=./__tmp
     95 	local sock= ok=
     96 
     97 	if $check_dead_sa; then
     98 		setkey_opts="-D -a"
     99 	else
    100 		setkey_opts="-D"
    101 	fi
    102 
    103 	while [ $n -ne 0 ]; do
    104 		ok=0
    105 		sleep 1
    106 		for sock in $SOCK_LOCAL $SOCK_PEER; do
    107 			export RUMP_SERVER=$sock
    108 			$HIJACKING setkey $setkey_opts > $tmpfile
    109 			$DEBUG && cat $tmpfile
    110 			if grep -q 'No SAD entries.' $tmpfile; then
    111 				ok=$((ok + 1))
    112 			fi
    113 		done
    114 		if [ $ok -eq 2 ]; then
    115 			return
    116 		fi
    117 
    118 		n=$((n - 1))
    119 	done
    120 
    121 	atf_fail "SAs didn't disappear after $time sec."
    122 }
    123 
    124 test_ipsec4_lifetime()
    125 {
    126 	local proto=$1
    127 	local algo=$2
    128 	local ip_local=10.0.0.1
    129 	local ip_peer=10.0.0.2
    130 	local outfile=./out
    131 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    132 	local algo_args="$(generate_algo_args $proto $algo)"
    133 	local lifetime=3
    134 	local buffertime=2
    135 
    136 	rump_server_crypto_start $SOCK_LOCAL netipsec
    137 	rump_server_crypto_start $SOCK_PEER netipsec
    138 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    139 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    140 
    141 	export RUMP_SERVER=$SOCK_LOCAL
    142 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    143 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
    144 	#atf_check -s exit:0 -o ignore rump.sysctl -w net.key.debug=0xff
    145 
    146 	export RUMP_SERVER=$SOCK_PEER
    147 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    148 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    149 	#atf_check -s exit:0 -o ignore rump.sysctl -w net.key.debug=0xff
    150 
    151 	extract_new_packets $BUS > $outfile
    152 
    153 	export RUMP_SERVER=$SOCK_LOCAL
    154 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    155 
    156 	extract_new_packets $BUS > $outfile
    157 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: ICMP echo request" \
    158 	    cat $outfile
    159 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: ICMP echo reply" \
    160 	    cat $outfile
    161 
    162 	# Set up SAs with lifetime 1 sec.
    163 	setup_sasp $proto "$algo_args" $ip_local $ip_peer 1
    164 
    165 	# Check the SAs have been expired
    166 	test_sad_disapper_until $((1 + $buffertime)) false
    167 
    168 	# Clean up SPs
    169 	export RUMP_SERVER=$SOCK_LOCAL
    170 	atf_check -s exit:0 -o empty $HIJACKING setkey -F -P
    171 	export RUMP_SERVER=$SOCK_PEER
    172 	atf_check -s exit:0 -o empty $HIJACKING setkey -F -P
    173 
    174 	# Set up SAs with lifetime with $lifetime
    175 	setup_sasp $proto "$algo_args" $ip_local $ip_peer $lifetime
    176 
    177 	# Use the SAs; this will create a reference from an SP to an SA
    178 	export RUMP_SERVER=$SOCK_LOCAL
    179 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    180 
    181 	extract_new_packets $BUS > $outfile
    182 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: $proto_cap" \
    183 	    cat $outfile
    184 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: $proto_cap" \
    185 	    cat $outfile
    186 
    187 	# Check the SAs have been expired
    188 	test_sad_disapper_until $((lifetime + $buffertime)) true
    189 
    190 	export RUMP_SERVER=$SOCK_LOCAL
    191 	atf_check -s not-exit:0 -o match:'0 packets received' \
    192 	    rump.ping -c 1 -n -w 1 $ip_peer
    193 
    194 	test_flush_entries $SOCK_LOCAL
    195 	test_flush_entries $SOCK_PEER
    196 }
    197 
    198 test_ipsec6_lifetime()
    199 {
    200 	local proto=$1
    201 	local algo=$2
    202 	local ip_local=fd00::1
    203 	local ip_peer=fd00::2
    204 	local outfile=./out
    205 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    206 	local algo_args="$(generate_algo_args $proto $algo)"
    207 	local lifetime=3
    208 	local buffertime=2
    209 
    210 	rump_server_crypto_start $SOCK_LOCAL netinet6 netipsec
    211 	rump_server_crypto_start $SOCK_PEER netinet6 netipsec
    212 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    213 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    214 
    215 	export RUMP_SERVER=$SOCK_LOCAL
    216 	atf_check -s exit:0 rump.sysctl -q -w net.inet6.ip6.dad_count=0
    217 	atf_check -s exit:0 rump.ifconfig shmif0 inet6 $ip_local
    218 
    219 	export RUMP_SERVER=$SOCK_PEER
    220 	atf_check -s exit:0 rump.sysctl -q -w net.inet6.ip6.dad_count=0
    221 	atf_check -s exit:0 rump.ifconfig shmif0 inet6 $ip_peer
    222 
    223 	extract_new_packets $BUS > $outfile
    224 
    225 	export RUMP_SERVER=$SOCK_LOCAL
    226 	atf_check -s exit:0 -o ignore rump.ping6 -c 1 -n -X 3 $ip_peer
    227 
    228 	extract_new_packets $BUS > $outfile
    229 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: ICMP6, echo request" \
    230 	    cat $outfile
    231 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: ICMP6, echo reply" \
    232 	    cat $outfile
    233 
    234 	# Set up SAs with lifetime 1 sec.
    235 	setup_sasp $proto "$algo_args" $ip_local $ip_peer 1
    236 
    237 	# Check the SAs have been expired
    238 	test_sad_disapper_until $((1 + $buffertime)) false
    239 
    240 	# Clean up SPs
    241 	export RUMP_SERVER=$SOCK_LOCAL
    242 	atf_check -s exit:0 -o empty $HIJACKING setkey -F -P
    243 	export RUMP_SERVER=$SOCK_PEER
    244 	atf_check -s exit:0 -o empty $HIJACKING setkey -F -P
    245 
    246 	# Set up SAs with lifetime with $lifetime
    247 	setup_sasp $proto "$algo_args" $ip_local $ip_peer $lifetime
    248 
    249 	# Use the SAs; this will create a reference from an SP to an SA
    250 	export RUMP_SERVER=$SOCK_LOCAL
    251 	atf_check -s exit:0 -o ignore rump.ping6 -c 1 -n -X 3 $ip_peer
    252 
    253 	extract_new_packets $BUS > $outfile
    254 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: $proto_cap" \
    255 	    cat $outfile
    256 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: $proto_cap" \
    257 	    cat $outfile
    258 
    259 	# Check the SAs have been expired
    260 	test_sad_disapper_until $((lifetime + $buffertime)) true
    261 
    262 	export RUMP_SERVER=$SOCK_LOCAL
    263 	atf_check -s not-exit:0 -o match:'0 packets received' \
    264 	    rump.ping6 -c 1 -n -X 1 $ip_peer
    265 
    266 	test_flush_entries $SOCK_LOCAL
    267 	test_flush_entries $SOCK_PEER
    268 }
    269 
    270 test_lifetime_common()
    271 {
    272 	local ipproto=$1
    273 	local proto=$2
    274 	local algo=$3
    275 
    276 	if [ $ipproto = ipv4 ]; then
    277 		test_ipsec4_lifetime $proto $algo
    278 	else
    279 		test_ipsec6_lifetime $proto $algo
    280 	fi
    281 }
    282 
    283 add_test_lifetime()
    284 {
    285 	local ipproto=$1
    286 	local proto=$2
    287 	local algo=$3
    288 	local _algo=$(echo $algo | sed 's/-//g')
    289 	local name= desc=
    290 
    291 	name="ipsec_lifetime_${ipproto}_${proto}_${_algo}"
    292 	desc="Tests of lifetime of IPsec ($ipproto) with $proto ($algo)"
    293 
    294 	atf_test_case ${name} cleanup
    295 	eval "
    296 	    ${name}_head() {
    297 	        atf_set descr \"$desc\"
    298 	        atf_set require.progs rump_server setkey
    299 	    }
    300 	    ${name}_body() {
    301 	        test_lifetime_common $ipproto $proto $algo
    302 	        rump_server_destroy_ifaces
    303 	    }
    304 	    ${name}_cleanup() {
    305 	        \$DEBUG && dump
    306 	        cleanup
    307 	    }
    308 	"
    309 	atf_add_test_case ${name}
    310 }
    311 
    312 test_update()
    313 {
    314 	local proto=$1
    315 	local algo=$2
    316 	local update=$3
    317 	local ip_local=10.0.0.1
    318 	local ip_peer=10.0.0.2
    319 	local algo_args="$(generate_algo_args $proto $algo)"
    320 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    321 	local outfile=./out
    322 
    323 	rump_server_crypto_start $SOCK_LOCAL netipsec
    324 	rump_server_crypto_start $SOCK_PEER netipsec
    325 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    326 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    327 
    328 	export RUMP_SERVER=$SOCK_LOCAL
    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_local/24
    331 
    332 	export RUMP_SERVER=$SOCK_PEER
    333 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    334 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    335 
    336 	setup_sasp $proto "$algo_args" $ip_local $ip_peer 100 $update
    337 
    338 	extract_new_packets $BUS > $outfile
    339 
    340 	export RUMP_SERVER=$SOCK_LOCAL
    341 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    342 
    343 	extract_new_packets $BUS > $outfile
    344 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: $proto_cap" \
    345 	    cat $outfile
    346 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: $proto_cap" \
    347 	    cat $outfile
    348 }
    349 
    350 add_test_update()
    351 {
    352 	local proto=$1
    353 	local algo=$2
    354 	local update=$3
    355 	local _update=$(echo $update |tr 'a-z' 'A-Z')
    356 	local _algo=$(echo $algo | sed 's/-//g')
    357 	local name= desc=
    358 
    359 	desc="Tests trying to udpate $_update of $proto ($algo)"
    360 	name="ipsec_update_${update}_${proto}_${_algo}"
    361 
    362 	atf_test_case ${name} cleanup
    363 	eval "
    364 	    ${name}_head() {
    365 	        atf_set descr \"$desc\"
    366 	        atf_set require.progs rump_server setkey
    367 	    }
    368 	    ${name}_body() {
    369 	        test_update $proto $algo $update
    370 	        rump_server_destroy_ifaces
    371 	    }
    372 	    ${name}_cleanup() {
    373 	        \$DEBUG && dump
    374 	        cleanup
    375 	    }
    376 	"
    377 	atf_add_test_case ${name}
    378 }
    379 
    380 test_getspi_update()
    381 {
    382 	local proto=$1
    383 	local algo=$2
    384 	local ip_local=10.0.0.1
    385 	local ip_peer=10.0.0.2
    386 	local algo_args="$(generate_algo_args $proto $algo)"
    387 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    388 	local outfile=./out
    389 
    390 	rump_server_crypto_start $SOCK_LOCAL netipsec
    391 	rump_server_crypto_start $SOCK_PEER netipsec
    392 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    393 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    394 
    395 	export RUMP_SERVER=$SOCK_LOCAL
    396 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    397 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
    398 
    399 	export RUMP_SERVER=$SOCK_PEER
    400 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    401 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    402 
    403 	setup_sasp $proto "$algo_args" $ip_local $ip_peer 100 getspi
    404 
    405 	extract_new_packets $BUS > $outfile
    406 
    407 	export RUMP_SERVER=$SOCK_LOCAL
    408 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    409 
    410 	extract_new_packets $BUS > $outfile
    411 	atf_check -s exit:0 -o match:"$ip_local > $ip_peer: $proto_cap" \
    412 	    cat $outfile
    413 	atf_check -s exit:0 -o match:"$ip_peer > $ip_local: $proto_cap" \
    414 	    cat $outfile
    415 }
    416 
    417 add_test_getspi_update()
    418 {
    419 	local proto=$1
    420 	local algo=$2
    421 	local _algo=$(echo $algo | sed 's/-//g')
    422 	local name= desc=
    423 
    424 	desc="Tests trying to getspi and udpate SA of $proto ($algo)"
    425 	name="ipsec_getspi_update_sa_${proto}_${_algo}"
    426 
    427 	atf_test_case ${name} cleanup
    428 	eval "
    429 	    ${name}_head() {
    430 	        atf_set descr \"$desc\"
    431 	        atf_set require.progs rump_server setkey
    432 	    }
    433 	    ${name}_body() {
    434 	        test_getspi_update $proto $algo
    435 	        rump_server_destroy_ifaces
    436 	    }
    437 	    ${name}_cleanup() {
    438 	        \$DEBUG && dump
    439 	        cleanup
    440 	    }
    441 	"
    442 	atf_add_test_case ${name}
    443 }
    444 
    445 add_sa()
    446 {
    447 	local proto=$1
    448 	local algo_args="$2"
    449 	local ip_local=$3
    450 	local ip_peer=$4
    451 	local lifetime=$5
    452 	local spi=$6
    453 	local tmpfile=./tmp
    454 	local extra=
    455 
    456 	export RUMP_SERVER=$SOCK_LOCAL
    457 	cat > $tmpfile <<-EOF
    458 	add $ip_local $ip_peer $proto $((spi)) -lh $lifetime -ls $lifetime $algo_args;
    459 	add $ip_peer $ip_local $proto $((spi + 1)) -lh $lifetime -ls $lifetime $algo_args;
    460 	$extra
    461 	EOF
    462 	$DEBUG && cat $tmpfile
    463 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    464 	$DEBUG && $HIJACKING setkey -D
    465 	# XXX it can be expired if $lifetime is very short
    466 	#check_sa_entries $SOCK_LOCAL $ip_local $ip_peer
    467 
    468 	export RUMP_SERVER=$SOCK_PEER
    469 	cat > $tmpfile <<-EOF
    470 	add $ip_local $ip_peer $proto $((spi)) -lh $lifetime -ls $lifetime $algo_args;
    471 	add $ip_peer $ip_local $proto $((spi + 1)) -lh $lifetime -ls $lifetime $algo_args;
    472 	$extra
    473 	EOF
    474 	$DEBUG && cat $tmpfile
    475 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    476 	$DEBUG && $HIJACKING setkey -D
    477 	# XXX it can be expired if $lifetime is very short
    478 	#check_sa_entries $SOCK_PEER $ip_local $ip_peer
    479 }
    480 
    481 delete_sa()
    482 {
    483 	local proto=$1
    484 	local ip_local=$2
    485 	local ip_peer=$3
    486 	local spi=$4
    487 	local tmpfile=./tmp
    488 	local extra=
    489 
    490 	export RUMP_SERVER=$SOCK_LOCAL
    491 	cat > $tmpfile <<-EOF
    492 	delete $ip_local $ip_peer $proto $((spi));
    493 	delete $ip_peer $ip_local $proto $((spi + 1));
    494 	EOF
    495 	$DEBUG && cat $tmpfile
    496 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    497 	$DEBUG && $HIJACKING setkey -D
    498 
    499 	export RUMP_SERVER=$SOCK_PEER
    500 	cat > $tmpfile <<-EOF
    501 	delete $ip_local $ip_peer $proto $((spi));
    502 	delete $ip_peer $ip_local $proto $((spi + 1));
    503 	EOF
    504 	$DEBUG && cat $tmpfile
    505 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    506 	$DEBUG && $HIJACKING setkey -D
    507 }
    508 
    509 check_packet_spi()
    510 {
    511 	local outfile=$1
    512 	local ip_local=$2
    513 	local ip_peer=$3
    514 	local proto=$4
    515 	local spi=$5
    516 	local spistr=
    517 
    518 	$DEBUG && cat $outfile
    519 	spistr=$(printf "%08x" $spi)
    520 	atf_check -s exit:0 \
    521 	    -o match:"$ip_local > $ip_peer: $proto_cap\(spi=0x$spistr," \
    522 	    cat $outfile
    523 	spistr=$(printf "%08x" $((spi + 1)))
    524 	atf_check -s exit:0 \
    525 	    -o match:"$ip_peer > $ip_local: $proto_cap\(spi=0x$spistr," \
    526 	    cat $outfile
    527 }
    528 
    529 wait_sa_disappeared()
    530 {
    531 	local spi=$1
    532 	local i=
    533 
    534 	export RUMP_SERVER=$SOCK_LOCAL
    535 	for i in $(seq 1 10); do
    536 		$HIJACKING setkey -D |grep -q "spi=$spi"
    537 		[ $? != 0 ] && break
    538 		sleep 1
    539 	done
    540 	if [ $i -eq 10 ]; then
    541 		atf_fail "SA (spi=$spi) didn't disappear in 10s"
    542 	fi
    543 	export RUMP_SERVER=$SOCK_PEER
    544 	for i in $(seq 1 10); do
    545 		$HIJACKING setkey -D |grep -q "spi=$spi"
    546 		[ $? != 0 ] && break
    547 		sleep 1
    548 	done
    549 	if [ $i -eq 10 ]; then
    550 		atf_fail "SA (spi=$spi) didn't disappear in 10s"
    551 	fi
    552 }
    553 
    554 test_spi()
    555 {
    556 	local proto=$1
    557 	local algo=$2
    558 	local preferred=$3
    559 	local method=$4
    560 	local ip_local=10.0.0.1
    561 	local ip_peer=10.0.0.2
    562 	local algo_args="$(generate_algo_args $proto $algo)"
    563 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    564 	local outfile=./out
    565 	local spistr=
    566 	local longtime= shorttime=
    567 
    568 	if [ $method = timeout -a $preferred = new ]; then
    569 		skip_if_qemu
    570 	fi
    571 
    572 	if [ $method = delete ]; then
    573 		shorttime=100
    574 		longtime=100
    575 	else
    576 		shorttime=3
    577 		longtime=6
    578 	fi
    579 
    580 	rump_server_crypto_start $SOCK_LOCAL netipsec
    581 	rump_server_crypto_start $SOCK_PEER netipsec
    582 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    583 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    584 
    585 	export RUMP_SERVER=$SOCK_LOCAL
    586 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    587 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
    588 	if [ $preferred = old ]; then
    589 		atf_check -s exit:0 rump.sysctl -q -w net.key.prefered_oldsa=1
    590 	fi
    591 
    592 	export RUMP_SERVER=$SOCK_PEER
    593 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    594 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    595 	if [ $preferred = old ]; then
    596 		atf_check -s exit:0 rump.sysctl -q -w net.key.prefered_oldsa=1
    597 	fi
    598 
    599 	setup_sasp $proto "$algo_args" $ip_local $ip_peer 100
    600 
    601 	extract_new_packets $BUS > $outfile
    602 
    603 	export RUMP_SERVER=$SOCK_LOCAL
    604 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    605 	extract_new_packets $BUS > $outfile
    606 	check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    607 
    608 	# Add a new SA with a different SPI
    609 	add_sa $proto "$algo_args" $ip_local $ip_peer $longtime 10010
    610 
    611 	export RUMP_SERVER=$SOCK_LOCAL
    612 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    613 	extract_new_packets $BUS > $outfile
    614 	if [ $preferred = old ]; then
    615 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    616 	else
    617 		# The new SA is preferred
    618 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10010
    619 	fi
    620 
    621 	# Add another SA with a different SPI
    622 	add_sa $proto "$algo_args" $ip_local $ip_peer $shorttime 10020
    623 
    624 	export RUMP_SERVER=$SOCK_LOCAL
    625 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    626 	extract_new_packets $BUS > $outfile
    627 	if [ $preferred = old ]; then
    628 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    629 	else
    630 		# The newest SA is preferred
    631 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10020
    632 	fi
    633 
    634 	if [ $method = delete ]; then
    635 		delete_sa $proto $ip_local $ip_peer 10020
    636 	else
    637 		wait_sa_disappeared 10020
    638 	fi
    639 
    640 	export RUMP_SERVER=$SOCK_LOCAL
    641 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    642 	extract_new_packets $BUS > $outfile
    643 	if [ $preferred = old ]; then
    644 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    645 	else
    646 		# The newest one is removed and the second one is used
    647 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10010
    648 	fi
    649 
    650 	if [ $method = delete ]; then
    651 		delete_sa $proto $ip_local $ip_peer 10010
    652 	else
    653 		wait_sa_disappeared 10010
    654 	fi
    655 
    656 	export RUMP_SERVER=$SOCK_LOCAL
    657 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    658 	extract_new_packets $BUS > $outfile
    659 	if [ $preferred = old ]; then
    660 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    661 	else
    662 		# The second one is removed and the original one is used
    663 		check_packet_spi $outfile $ip_local $ip_peer $proto_cap 10000
    664 	fi
    665 }
    666 
    667 add_test_spi()
    668 {
    669 	local proto=$1
    670 	local algo=$2
    671 	local preferred=$3
    672 	local method=$4
    673 	local _algo=$(echo $algo | sed 's/-//g')
    674 	local name= desc=
    675 
    676 	desc="Tests SAs with different SPIs of $proto ($algo) ($preferred SA preferred) ($method)"
    677 	name="ipsec_spi_${proto}_${_algo}_preferred_${preferred}_${method}"
    678 
    679 	atf_test_case ${name} cleanup
    680 	eval "
    681 	    ${name}_head() {
    682 	        atf_set descr \"$desc\"
    683 	        atf_set require.progs rump_server setkey
    684 	    }
    685 	    ${name}_body() {
    686 	        test_spi $proto $algo $preferred $method
    687 	        rump_server_destroy_ifaces
    688 	    }
    689 	    ${name}_cleanup() {
    690 	        \$DEBUG && dump
    691 	        cleanup
    692 	    }
    693 	"
    694 	atf_add_test_case ${name}
    695 }
    696 
    697 setup_sp()
    698 {
    699 	local proto=$1
    700 	local algo_args="$2"
    701 	local ip_local=$3
    702 	local ip_peer=$4
    703 	local tmpfile=./tmp
    704 
    705 	export RUMP_SERVER=$SOCK_LOCAL
    706 	cat > $tmpfile <<-EOF
    707 	spdadd $ip_local $ip_peer any -P out ipsec $proto/transport//require;
    708 	spdadd $ip_peer $ip_local any -P in ipsec $proto/transport//require;
    709 	EOF
    710 	$DEBUG && cat $tmpfile
    711 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    712 	check_sp_entries $SOCK_LOCAL $ip_local $ip_peer
    713 
    714 	export RUMP_SERVER=$SOCK_PEER
    715 	cat > $tmpfile <<-EOF
    716 	spdadd $ip_peer $ip_local any -P out ipsec $proto/transport//require;
    717 	spdadd $ip_local $ip_peer any -P in ipsec $proto/transport//require;
    718 	EOF
    719 	$DEBUG && cat $tmpfile
    720 	atf_check -s exit:0 -o empty $HIJACKING setkey -c < $tmpfile
    721 	check_sp_entries $SOCK_PEER $ip_peer $ip_local
    722 }
    723 
    724 test_nosa()
    725 {
    726 	local proto=$1
    727 	local algo=$2
    728 	local update=$3
    729 	local ip_local=10.0.0.1
    730 	local ip_peer=10.0.0.2
    731 	local algo_args="$(generate_algo_args $proto $algo)"
    732 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    733 	local outfile=./out
    734 
    735 	rump_server_crypto_start $SOCK_LOCAL netipsec
    736 	rump_server_crypto_start $SOCK_PEER netipsec
    737 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    738 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    739 
    740 	export RUMP_SERVER=$SOCK_LOCAL
    741 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    742 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
    743 
    744 	export RUMP_SERVER=$SOCK_PEER
    745 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    746 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    747 
    748 	setup_sp $proto "$algo_args" $ip_local $ip_peer
    749 
    750 	extract_new_packets $BUS > $outfile
    751 
    752 	export RUMP_SERVER=$SOCK_LOCAL
    753 	# It doesn't work because there is no SA
    754 	atf_check -s not-exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    755 }
    756 
    757 add_test_nosa()
    758 {
    759 	local proto=$1
    760 	local algo=$2
    761 	local _algo=$(echo $algo | sed 's/-//g')
    762 	local name= desc=
    763 
    764 	desc="Tests SPs with no relevant SAs with $proto ($algo)"
    765 	name="ipsec_nosa_${proto}_${_algo}"
    766 
    767 	atf_test_case ${name} cleanup
    768 	eval "
    769 	    ${name}_head() {
    770 	        atf_set descr \"$desc\"
    771 	        atf_set require.progs rump_server setkey
    772 	    }
    773 	    ${name}_body() {
    774 	        test_nosa $proto $algo
    775 	        rump_server_destroy_ifaces
    776 	    }
    777 	    ${name}_cleanup() {
    778 	        \$DEBUG && dump
    779 	        cleanup
    780 	    }
    781 	"
    782 	atf_add_test_case ${name}
    783 }
    784 
    785 test_multiple_sa()
    786 {
    787 	local proto=$1
    788 	local algo=$2
    789 	local update=$3
    790 	local ip_local=10.0.0.1
    791 	local ip_peer=10.0.0.2
    792 	local ip_peer2=10.0.0.3
    793 	local algo_args="$(generate_algo_args $proto $algo)"
    794 	local proto_cap=$(echo $proto | tr 'a-z' 'A-Z')
    795 	local outfile=./out
    796 
    797 	rump_server_crypto_start $SOCK_LOCAL netipsec
    798 	rump_server_crypto_start $SOCK_PEER netipsec
    799 	rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
    800 	rump_server_add_iface $SOCK_PEER shmif0 $BUS
    801 
    802 	export RUMP_SERVER=$SOCK_LOCAL
    803 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    804 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_local/24
    805 
    806 	export RUMP_SERVER=$SOCK_PEER
    807 	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
    808 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer/24
    809 	atf_check -s exit:0 rump.ifconfig shmif0 $ip_peer2/24 alias
    810 
    811 	setup_sp $proto "$algo_args" "$ip_local" "0.0.0.0/0"
    812 
    813 	extract_new_packets $BUS > $outfile
    814 
    815 	export RUMP_SERVER=$SOCK_LOCAL
    816 	# There is no SA, so ping should fail
    817 	atf_check -s not-exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    818 	atf_check -s not-exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer2
    819 
    820 	add_sa $proto "$algo_args" $ip_local $ip_peer 100 10000
    821 
    822 	export RUMP_SERVER=$SOCK_LOCAL
    823 	# There is only an SA for $ip_peer, so ping to $ip_peer2 should fail
    824 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    825 	atf_check -s not-exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer2
    826 
    827 	add_sa $proto "$algo_args" $ip_local $ip_peer2 100 10010
    828 
    829 	export RUMP_SERVER=$SOCK_LOCAL
    830 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer
    831 	atf_check -s exit:0 -o ignore rump.ping -c 1 -n -w 3 $ip_peer2
    832 
    833 	export RUMP_SERVER=$SOCK_LOCAL
    834 	atf_check -s exit:0 -o match:"$proto/transport//require" \
    835 	    $HIJACKING setkey -D -P
    836 	# Check if the policy isn't modified accidentally
    837 	atf_check -s exit:0 -o not-match:"$proto/transport/.+\-.+/require" \
    838 	    $HIJACKING setkey -D -P
    839 	export RUMP_SERVER=$SOCK_PEER
    840 	atf_check -s exit:0 -o match:"$proto/transport//require" \
    841 	    $HIJACKING setkey -D -P
    842 	# Check if the policy isn't modified accidentally
    843 	atf_check -s exit:0 -o not-match:"$proto/transport/.+\-.+/require" \
    844 	    $HIJACKING setkey -D -P
    845 }
    846 
    847 add_test_multiple_sa()
    848 {
    849 	local proto=$1
    850 	local algo=$2
    851 	local _algo=$(echo $algo | sed 's/-//g')
    852 	local name= desc=
    853 
    854 	desc="Tests multiple SAs with $proto ($algo)"
    855 	name="ipsec_multiple_sa_${proto}_${_algo}"
    856 
    857 	atf_test_case ${name} cleanup
    858 	eval "
    859 	    ${name}_head() {
    860 	        atf_set descr \"$desc\"
    861 	        atf_set require.progs rump_server setkey
    862 	    }
    863 	    ${name}_body() {
    864 	        test_multiple_sa $proto $algo
    865 	        rump_server_destroy_ifaces
    866 	    }
    867 	    ${name}_cleanup() {
    868 	        \$DEBUG && dump
    869 	        cleanup
    870 	    }
    871 	"
    872 	atf_add_test_case ${name}
    873 }
    874 
    875 atf_init_test_cases()
    876 {
    877 	local algo=
    878 
    879 	for algo in $ESP_ENCRYPTION_ALGORITHMS_MINIMUM; do
    880 		add_test_lifetime ipv4 esp $algo
    881 		add_test_lifetime ipv6 esp $algo
    882 		add_test_update esp $algo sa
    883 		add_test_update esp $algo sp
    884 		add_test_getspi_update esp $algo
    885 		add_test_spi esp $algo new delete
    886 		add_test_spi esp $algo old delete
    887 		add_test_spi esp $algo new timeout
    888 		add_test_spi esp $algo old timeout
    889 		add_test_nosa esp $algo
    890 		add_test_multiple_sa esp $algo
    891 	done
    892 	for algo in $AH_AUTHENTICATION_ALGORITHMS_MINIMUM; do
    893 		add_test_lifetime ipv4 ah $algo
    894 		add_test_lifetime ipv6 ah $algo
    895 		add_test_update ah $algo sa
    896 		add_test_update ah $algo sp
    897 		add_test_getspi_update ah $algo
    898 		add_test_spi ah $algo new delete
    899 		add_test_spi ah $algo old delete
    900 		add_test_spi ah $algo new timeout
    901 		add_test_spi ah $algo old timeout
    902 		add_test_nosa ah $algo
    903 		add_test_multiple_sa ah $algo
    904 	done
    905 }
    906