1#!/bin/sh
2# Copyright (c) 2016 Red Hat Inc.,  All Rights Reserved.
3# Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; either version 2 of
8# the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it would be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, see <http://www.gnu.org/licenses/>.
17#
18# Author: Hangbin Liu <haliu@redhat.com>
19#
20#######################################################################
21
22. test_net.sh
23
24# Authenticated encryption with associated data
25AEALGO="rfc4106_128"
26# Encryption algorithm
27EALGO="des3_ede"
28# Authentication algorithm
29AALGO="sha1"
30# Compression algorithm
31CALGO="deflate"
32
33IPSEC_REQUESTS="500"
34IPSEC_SIZE_ARRAY="${IPSEC_SIZE_ARRAY:-10 100 1000 2000 10000 65000}"
35
36while getopts "hl:m:p:s:S:k:A:e:a:c:r:6" opt; do
37	case "$opt" in
38	h)
39		echo "Usage:"
40		echo "h        help"
41		echo "l n      n is the number of test link when tests run"
42		echo "m x      x is ipsec mode, could be transport / tunnel"
43		echo "p x      x is ipsec protocol, could be ah / esp / comp"
44		echo "s x      x is icmp messge size array"
45		echo "S n      n is IPsec SPI value"
46		echo "k x      key for vti interface"
47		echo "A x      Authenticated encryption with associated data algorithm"
48		echo "e x      Encryption algorithm"
49		echo "a x      Authentication algorithm"
50		echo "c x      Compression algorithm"
51		echo "r x      Num of requests, PING_MAX or netstress' '-r' opt"
52		echo "6        run over IPv6"
53		exit 0
54	;;
55	l) LINK_NUM=$OPTARG ;;
56	m) IPSEC_MODE=$OPTARG ;;
57	p) IPSEC_PROTO=$OPTARG ;;
58	s) IPSEC_SIZE_ARRAY="$OPTARG" ;;
59	S) SPI=$OPTARG ;;
60	k) VTI_KEY=$OPTARG ;;
61	A) AEALGO=$OPTARG ;;
62	e) EALGO=$OPTARG ;;
63	a) AALGO=$OPTARG ;;
64	c) CALGO=$OPTARG ;;
65	r) IPSEC_REQUESTS="$OPTARG" ;;
66	6) # skip, test_net library already processed it
67	;;
68	*) tst_brkm TBROK "unknown option: $opt" ;;
69	esac
70done
71
72get_key()
73{
74	local bits=$1
75	local xdg_num=$(( $bits / 4 ))
76	echo "0x$(tr -dc "[:xdigit:]" < /dev/urandom | head -c$xdg_num)"
77}
78
79case $AEALGO in
80rfc4106_128|rfc4543_128) AEALGO_KEY=$(get_key 160) ;;
81rfc4106_192|rfc4543_192) AEALGO_KEY=$(get_key 224) ;;
82rfc4106_256|rfc4543_256) AEALGO_KEY=$(get_key 288) ;;
83rfc4309_128) AEALGO_KEY=$(get_key 152) ;;
84rfc4309_192) AEALGO_KEY=$(get_key 216) ;;
85rfc4309_256) AEALGO_KEY=$(get_key 280) ;;
86esac
87
88case $EALGO in
89des) EALGO_KEY=$(get_key 64) ;;
90des3_ede) EALGO_KEY=$(get_key 192) ;;
91cast5) EALGO_KEY=$(get_key 128) ;;
92blowfish) EALGO_KEY=$(get_key 448) ;;
93aes|twofish|camellia|serpent) EALGO_KEY=$(get_key 256) ;;
94*) tst_brkm TBROK "unknown enc alg: $EALGO" ;;
95esac
96
97case $AALGO in
98sha1|rmd160) AALGO_KEY=$(get_key 160) ;;
99sha256) AALGO_KEY=$(get_key 256) ;;
100sha384) AALGO_KEY=$(get_key 384) ;;
101sha512) AALGO_KEY=$(get_key 512) ;;
102*) tst_brkm TBROK "unknown auth alg: $AALGO" ;;
103esac
104
105SPI=${SPI:-1000}
106VTI_KEY=${VTI_KEY:-10}
107cleanup_vti=
108ALG=
109ALGR=
110
111# tst_ipsec_cleanup: flush ipsec state and policy rules
112tst_ipsec_cleanup()
113{
114	ip xfrm state flush
115	ip xfrm policy flush
116	tst_rhost_run -c "ip xfrm state flush && ip xfrm policy flush"
117
118	if [ -n "$cleanup_vti" ]; then
119		ip li del $cleanup_vti 2>/dev/null
120		tst_rhost_run -c "ip li del $cleanup_vti 2>/dev/null"
121	fi
122
123	[ "$TST_NEEDS_TMPDIR" = 1 ] && tst_rmdir
124}
125
126ipsec_set_algoline()
127{
128	case $IPSEC_PROTO in
129	ah)
130		ALG='auth hmac('$AALGO') '$AALGO_KEY
131		ALGR='auth hmac\('$AALGO'\) '$AALGO_KEY
132		;;
133	esp)
134		ALG="enc $EALGO $EALGO_KEY auth "'hmac('$AALGO') '$AALGO_KEY
135		ALGR="enc $EALGO $EALGO_KEY auth "'hmac\('$AALGO'\) '$AALGO_KEY
136		;;
137	esp_aead)
138		case $AEALGO in
139		rfc4106_128|rfc4106_192|rfc4106_256)
140			ALG="aead "'rfc4106(gcm(aes))'" $AEALGO_KEY 128"
141			ALGR="aead "'rfc4106\(gcm\(aes\)\)'" $AEALGO_KEY 128"
142			;;
143		rfc4309_128|rfc4309_192|rfc4309_256)
144			ALG="aead "'rfc4309(ccm(aes))'" $AEALGO_KEY 128"
145			ALGR="aead "'rfc4309\(ccm\(aes\)\)'" $AEALGO_KEY 128"
146			;;
147		rfc4543_128|rfc4543_192|rfc4543_256)
148			ALG="aead "'rfc4543(gcm(aes))'" $AEALGO_KEY 128"
149			ALGR="aead "'rfc4543\(gcm\(aes\)\)'" $AEALGO_KEY 128"
150			;;
151		esac
152		;;
153	comp)
154		ALG="comp $CALGO"
155		ALGR=$ALG
156		;;
157	*)
158		tst_brkm TCONF "tst_ipsec protocol mismatch"
159		;;
160	esac
161}
162
163ipsec_try()
164{
165	local output="$($@ 2>&1 || echo 'TERR')"
166
167	if echo "$output" | grep -q "TERR"; then
168		echo "$output" | grep -q \
169			'RTNETLINK answers: Function not implemented' && \
170			tst_brkm TCONF "'$@': not implemented"
171		echo "$output" | grep -q \
172			'RTNETLINK answers: Operation not supported' && \
173			tst_brkm TCONF "'$@': not supported (maybe missing 'ip${TST_IPV6}_vti' kernel module)"
174		tst_brkm TBROK "$@ failed: $output"
175	fi
176}
177
178# tst_ipsec target src_addr dst_addr: config ipsec
179#
180# target: target of the configuration host ( lhost / rhost )
181# src_addr: source IP address
182# dst_addr: destination IP address
183tst_ipsec()
184{
185	if [ $# -ne 3 ]; then
186		tst_brkm TCONF "tst_ipsec parameter mismatch"
187	fi
188
189	local target=$1
190	local src=$2
191	local dst=$3
192	local mode=$IPSEC_MODE
193	local p="proto $IPSEC_PROTO"
194	[ "$IPSEC_PROTO" = "esp_aead" ] && p="proto esp"
195
196	ipsec_set_algoline
197
198	if [ $target = lhost ]; then
199		local spi_1="0x$SPI"
200		local spi_2="0x$(( $SPI + 1 ))"
201		ipsec_try ip xfrm state add src $src dst $dst spi $spi_1 \
202			$p $ALG mode $mode sel src $src dst $dst
203		ROD ip xfrm state add src $dst dst $src spi $spi_2 \
204			$p $ALG mode $mode sel src $dst dst $src
205
206		ROD ip xfrm policy add src $src dst $dst dir out tmpl src $src \
207			dst $dst $p mode $mode
208		ROD ip xfrm policy add src $dst dst $src dir in tmpl src $dst \
209			dst $src $p mode $mode level use
210	elif [ $target = rhost ]; then
211		local spi_1="0x$(( $SPI + 1 ))"
212		local spi_2="0x$SPI"
213		tst_rhost_run -s -c "ip xfrm state add src $src dst $dst \
214			spi $spi_1 $p $ALGR mode $mode sel src $src dst $dst"
215		tst_rhost_run -s -c "ip xfrm state add src $dst dst $src \
216			spi $spi_2 $p $ALGR mode $mode sel src $dst dst $src"
217
218		tst_rhost_run -s -c "ip xfrm policy add src $src dst $dst \
219			dir out tmpl src $src dst $dst $p mode $mode"
220		tst_rhost_run -s -c "ip xfrm policy add src $dst dst $src dir \
221			in tmpl src $dst dst $src $p mode $mode level use"
222	fi
223}
224
225# tst_ipsec_vti target src_addr dst_addr vti_name
226#
227# target: target of the configuration host ( lhost / rhost )
228# src_addr: source IP address
229# dst_addr: destination IP address
230# vti_name: name of vti interface
231tst_ipsec_vti()
232{
233	if [ $# -ne 4 ]; then
234		tst_brkm TCONF "tst_ipsec_vti parameter mismatch"
235	fi
236
237	local target=$1
238	local src=$2
239	local dst=$3
240	local vti=$4
241	local m="mode $IPSEC_MODE"
242	local p="proto $IPSEC_PROTO"
243	[ "$IPSEC_PROTO" = "esp_aead" ] && p="proto esp"
244
245	local key="key $VTI_KEY"
246	local mrk="mark $VTI_KEY"
247	local type="type vti$TST_IPV6"
248	local d="dev $(tst_iface)"
249	local rd="dev $(tst_iface rhost)"
250
251	ip li add type vti help 2>&1 | grep -q vti || \
252		tst_brkm TCONF "iproute doesn't support 'vti'"
253
254	ipsec_set_algoline
255
256	local o_dir="src $src dst $dst"
257	local i_dir="src $dst dst $src"
258	local ipx="ip -${TST_IPV6:-4} xf"
259
260	cleanup_vti=$vti
261
262	if [ $target = lhost ]; then
263		ipsec_try ip li add $vti $type local $src remote $dst $key $d
264		ROD ip li set $vti up
265
266		local spi_1="spi 0x$SPI"
267		local spi_2="spi 0x$(( $SPI + 1 ))"
268		ipsec_try $ipx st add $o_dir $p $spi_1 $ALG $m
269		ROD $ipx st add $i_dir $p $spi_2 $ALG $m
270		ROD $ipx po add dir out tmpl $o_dir $p $m $mrk
271		ROD $ipx po add dir in tmpl $i_dir $p $m $mrk
272	elif [ $target = rhost ]; then
273		tst_rhost_run -s -c \
274			"ip li add $vti $type local $src remote $dst $key $rd"
275		tst_rhost_run -s -c "ip li set $vti up"
276
277		local spi_1="spi 0x$(( $SPI + 1 ))"
278		local spi_2="spi 0x$SPI"
279		tst_rhost_run -s -c "$ipx st add $o_dir $p $spi_1 $ALGR $m"
280		tst_rhost_run -s -c "$ipx st add $i_dir $p $spi_2 $ALGR $m"
281		tst_rhost_run -s -c "$ipx po add dir out tmpl $o_dir $p $m $mrk"
282		tst_rhost_run -s -c "$ipx po add dir in tmpl $i_dir $p $m $mrk"
283	fi
284}
285
286# Setup vti/vti6 interface for IPsec tunneling
287# The function sets variables:
288#  * tst_vti - vti interface name,
289#  * ip_loc_tun - local IP address on vti interface
290#  * ip_rmt_tun - remote IP address
291tst_ipsec_setup_vti()
292{
293	if_loc=$(tst_iface)
294	if_rmt=$(tst_iface rhost)
295
296	ip_loc=$(tst_ipaddr)
297	ip_rmt=$(tst_ipaddr rhost)
298
299	tst_vti="ltp_vti0"
300
301	tst_resm TINFO "Test vti$TST_IPV6 + IPsec[$IPSEC_PROTO/$IPSEC_MODE]"
302
303	tst_ipsec_vti lhost $ip_loc $ip_rmt $tst_vti
304	tst_ipsec_vti rhost $ip_rmt $ip_loc $tst_vti
305
306	local mask=
307	if [ "$TST_IPV6" ]; then
308		ip_loc_tun="${IPV6_NET32_UNUSED}::1";
309		ip_rmt_tun="${IPV6_NET32_UNUSED}::2";
310		mask=64
311		ROD ip -6 route add ${IPV6_NET32_UNUSED}::/$mask dev $tst_vti
312	else
313		ip_loc_tun="${IPV4_NET16_UNUSED}.1.1";
314		ip_rmt_tun="${IPV4_NET16_UNUSED}.1.2";
315		mask=30
316		ROD ip route add ${IPV4_NET16_UNUSED}.1.0/$mask dev $tst_vti
317	fi
318
319	tst_resm TINFO "Add IPs to vti tunnel, " \
320		       "loc: $ip_loc_tun/$mask, rmt: $ip_rmt_tun/$mask"
321
322	ROD ip a add $ip_loc_tun/$mask dev $tst_vti nodad
323	tst_rhost_run -s -c "ip a add $ip_rmt_tun/$mask dev $tst_vti"
324}
325