#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (c) 2018 Petr Vorel <pvorel@suse.cz>
# Copyright (c) 2016 Red Hat Inc., All Rights Reserved.
# Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
# Author: Hangbin Liu <haliu@redhat.com>
# Authenticated encryption with associated data
AEALGO="rfc4106_128"
# Encryption algorithm
EALGO="des3_ede"
# Authentication algorithm
AALGO="sha1"
# Compression algorithm
CALGO="deflate"
IPSEC_REQUESTS="500"
ipsec_lib_usage()
{
echo "l n n is the number of test link when tests run"
echo "m x x is ipsec mode, could be transport / tunnel"
echo "p x x is ipsec protocol, could be ah / esp / comp"
echo "s x x is icmp message size array"
echo "S n n is IPsec SPI value"
echo "k x key for vti interface"
echo "A x Authenticated encryption with associated data algorithm"
echo "e x Encryption algorithm"
echo "a x Authentication algorithm"
echo "c x Compression algorithm"
echo "r x Num of requests, PING_MAX or netstress' '-r' opt"
}
ipsec_lib_parse_args()
{
case "$1" in
l) LINK_NUM=$2;;
m) IPSEC_MODE=$2;;
p) IPSEC_PROTO=$2;;
s) TST_TEST_DATA="$2"; TST_TEST_DATA_IFS=":";;
S) SPI=$2;;
k) VTI_KEY=$2;;
A) AEALGO=$2;;
e) EALGO=$2;;
a) AALGO=$2;;
c) CALGO=$2;;
r) IPSEC_REQUESTS="$2";;
esac
}
ipsec_lib_setup()
{
case $AEALGO in
rfc4106_128|rfc4543_128) AEALGO_KEY=$(get_key 160);;
rfc4106_192|rfc4543_192) AEALGO_KEY=$(get_key 224);;
rfc4106_256|rfc4543_256) AEALGO_KEY=$(get_key 288);;
rfc4309_128) AEALGO_KEY=$(get_key 152);;
rfc4309_192) AEALGO_KEY=$(get_key 216);;
rfc4309_256) AEALGO_KEY=$(get_key 280);;
esac
case $EALGO in
des) EALGO_KEY=$(get_key 64);;
des3_ede) EALGO_KEY=$(get_key 192);;
cast5) EALGO_KEY=$(get_key 128);;
blowfish) EALGO_KEY=$(get_key 448);;
aes|twofish|camellia|serpent) EALGO_KEY=$(get_key 256);;
*) tst_brk TBROK "unknown enc alg: $EALGO";;
esac
case $AALGO in
sha1|rmd160) AALGO_KEY=$(get_key 160);;
sha256) AALGO_KEY=$(get_key 256);;
sha384) AALGO_KEY=$(get_key 384);;
sha512) AALGO_KEY=$(get_key 512);;
*) tst_brk TBROK "unknown auth alg: $AALGO";;
esac
SPI=${SPI:-1000}
VTI_KEY=${VTI_KEY:-10}
cleanup_vti=
ALG=
ALGR=
if [ -n "$IPSEC_MODE" ]; then
tst_net_run "tst_check_drivers xfrm_user" || \
tst_brk TCONF "xfrm_user driver not available on lhost or rhost"
cleanup_xfrm=1
fi
}
TST_OPTS="l:m:p:s:S:k:A:e:a:c:r:"
TST_PARSE_ARGS=ipsec_lib_parse_args
TST_SETUP=${TST_SETUP:-ipsec_lib_setup}
TST_USAGE=ipsec_lib_usage
. tst_net.sh
get_key()
{
local bits=$1
local bytes=$(( $bits / 8))
echo "0x$(hexdump -vn $bytes -e '1/1 "%02x"' /dev/urandom)"
}
tst_ipsec_setup()
{
ipsec_lib_setup
# Configure SAD/SPD
if [ -n "$IPSEC_MODE" -a -n "$IPSEC_PROTO" ]; then
tst_res TINFO "IPsec[$IPSEC_PROTO/$IPSEC_MODE]"
tst_ipsec lhost $(tst_ipaddr) $(tst_ipaddr rhost)
tst_ipsec rhost $(tst_ipaddr rhost) $(tst_ipaddr)
fi
}
# tst_ipsec_cleanup: flush ipsec state and policy rules
tst_ipsec_cleanup()
{
[ -z "$cleanup_xfrm" ] && return
ip xfrm state flush
ip xfrm policy flush
tst_rhost_run -c "ip xfrm state flush && ip xfrm policy flush"
if [ -n "$cleanup_vti" ]; then
ip li del $cleanup_vti 2>/dev/null
tst_rhost_run -c "ip li del $cleanup_vti 2>/dev/null"
fi
}
ipsec_set_algoline()
{
case $IPSEC_PROTO in
ah)
ALG='auth hmac('$AALGO') '$AALGO_KEY
ALGR='auth hmac\('$AALGO'\) '$AALGO_KEY
;;
esp)
ALG="enc $EALGO $EALGO_KEY auth "'hmac('$AALGO') '$AALGO_KEY
ALGR="enc $EALGO $EALGO_KEY auth "'hmac\('$AALGO'\) '$AALGO_KEY
;;
esp_aead)
case $AEALGO in
rfc4106_128|rfc4106_192|rfc4106_256)
ALG="aead "'rfc4106(gcm(aes))'" $AEALGO_KEY 128"
ALGR="aead "'rfc4106\(gcm\(aes\)\)'" $AEALGO_KEY 128"
;;
rfc4309_128|rfc4309_192|rfc4309_256)
ALG="aead "'rfc4309(ccm(aes))'" $AEALGO_KEY 128"
ALGR="aead "'rfc4309\(ccm\(aes\)\)'" $AEALGO_KEY 128"
;;
rfc4543_128|rfc4543_192|rfc4543_256)
ALG="aead "'rfc4543(gcm(aes))'" $AEALGO_KEY 128"
ALGR="aead "'rfc4543\(gcm\(aes\)\)'" $AEALGO_KEY 128"
;;
esac
;;
comp)
ALG="comp $CALGO"
ALGR=$ALG
;;
*)
tst_brk TCONF "tst_ipsec protocol mismatch"
;;
esac
}
# tst_ipsec target src_addr dst_addr: config ipsec
#
# target: target of the configuration host ( lhost / rhost )
# src_addr: source IP address
# dst_addr: destination IP address
tst_ipsec()
{
if [ $# -ne 3 ]; then
tst_brk TCONF "tst_ipsec parameter mismatch"
fi
local target=$1
local src=$2
local dst=$3
local mode=$IPSEC_MODE
local p="proto $IPSEC_PROTO"
[ "$IPSEC_PROTO" = "esp_aead" ] && p="proto esp"
ipsec_set_algoline
if [ $target = lhost ]; then
local spi_1="0x$SPI"
local spi_2="0x$(( $SPI + 1 ))"
TST_RTNL_CHK ip xfrm state add src $src dst $dst spi $spi_1 \
$p $ALG mode $mode sel src $src dst $dst
ROD ip xfrm state add src $dst dst $src spi $spi_2 \
$p $ALG mode $mode sel src $dst dst $src
ROD ip xfrm policy add src $src dst $dst dir out tmpl src $src \
dst $dst $p mode $mode
ROD ip xfrm policy add src $dst dst $src dir in tmpl src $dst \
dst $src $p mode $mode level use
elif [ $target = rhost ]; then
local spi_1="0x$(( $SPI + 1 ))"
local spi_2="0x$SPI"
tst_rhost_run -s -c "ip xfrm state add src $src dst $dst \
spi $spi_1 $p $ALGR mode $mode sel src $src dst $dst"
tst_rhost_run -s -c "ip xfrm state add src $dst dst $src \
spi $spi_2 $p $ALGR mode $mode sel src $dst dst $src"
tst_rhost_run -s -c "ip xfrm policy add src $src dst $dst \
dir out tmpl src $src dst $dst $p mode $mode"
tst_rhost_run -s -c "ip xfrm policy add src $dst dst $src dir \
in tmpl src $dst dst $src $p mode $mode level use"
fi
}
# tst_ipsec_vti target src_addr dst_addr vti_name
#
# target: target of the configuration host ( lhost / rhost )
# src_addr: source IP address
# dst_addr: destination IP address
# vti_name: name of vti interface
tst_ipsec_vti()
{
if [ $# -ne 4 ]; then
tst_brk TCONF "tst_ipsec_vti parameter mismatch"
fi
local target=$1
local src=$2
local dst=$3
local vti=$4
local m="mode $IPSEC_MODE"
local p="proto $IPSEC_PROTO"
[ "$IPSEC_PROTO" = "esp_aead" ] && p="proto esp"
local key="key $VTI_KEY"
local mrk="mark $VTI_KEY"
local type="type vti$TST_IPV6"
local d="dev $(tst_iface)"
local rd="dev $(tst_iface rhost)"
ip li add type vti help 2>&1 | grep -q vti || \
tst_brk TCONF "iproute doesn't support 'vti'"
ipsec_set_algoline
local o_dir="src $src dst $dst"
local i_dir="src $dst dst $src"
local ipx="ip -${TST_IPV6:-4} xf"
cleanup_vti=$vti
if [ $target = lhost ]; then
TST_RTNL_CHK ip li add $vti $type local $src remote $dst $key $d
ROD ip li set $vti up
local spi_1="spi 0x$SPI"
local spi_2="spi 0x$(( $SPI + 1 ))"
TST_RTNL_CHK $ipx st add $o_dir $p $spi_1 $ALG $m
ROD $ipx st add $i_dir $p $spi_2 $ALG $m
ROD $ipx po add dir out tmpl $o_dir $p $m $mrk
ROD $ipx po add dir in tmpl $i_dir $p $m $mrk
elif [ $target = rhost ]; then
tst_rhost_run -s -c \
"ip li add $vti $type local $src remote $dst $key $rd"
tst_rhost_run -s -c "ip li set $vti up"
local spi_1="spi 0x$(( $SPI + 1 ))"
local spi_2="spi 0x$SPI"
tst_rhost_run -s -c "$ipx st add $o_dir $p $spi_1 $ALGR $m"
tst_rhost_run -s -c "$ipx st add $i_dir $p $spi_2 $ALGR $m"
tst_rhost_run -s -c "$ipx po add dir out tmpl $o_dir $p $m $mrk"
tst_rhost_run -s -c "$ipx po add dir in tmpl $i_dir $p $m $mrk"
fi
}
# Setup vti/vti6 interface for IPsec tunneling
# The function sets variables:
# * tst_vti - vti interface name,
# * ip_loc_tun - local IP address on vti interface
# * ip_rmt_tun - remote IP address
tst_ipsec_setup_vti()
{
ipsec_lib_setup
if_loc=$(tst_iface)
if_rmt=$(tst_iface rhost)
ip_loc=$(tst_ipaddr)
ip_rmt=$(tst_ipaddr rhost)
tst_vti="ltp_vti0"
tst_res TINFO "Test vti$TST_IPV6 + IPsec[$IPSEC_PROTO/$IPSEC_MODE]"
tst_ipsec_vti lhost $ip_loc $ip_rmt $tst_vti
tst_ipsec_vti rhost $ip_rmt $ip_loc $tst_vti
local mask=
if [ "$TST_IPV6" ]; then
ip_loc_tun="${IPV6_NET32_UNUSED}::1";
ip_rmt_tun="${IPV6_NET32_UNUSED}::2";
mask=64
ROD ip -6 route add ${IPV6_NET32_UNUSED}::/$mask dev $tst_vti
else
ip_loc_tun="${IPV4_NET16_UNUSED}.1.1";
ip_rmt_tun="${IPV4_NET16_UNUSED}.1.2";
mask=30
ROD ip route add ${IPV4_NET16_UNUSED}.1.0/$mask dev $tst_vti
fi
tst_res TINFO "Add IPs to vti tunnel, " \
"loc: $ip_loc_tun/$mask, rmt: $ip_rmt_tun/$mask"
ROD ip a add $ip_loc_tun/$mask dev $tst_vti nodad
tst_rhost_run -s -c "ip a add $ip_rmt_tun/$mask dev $tst_vti"
}