cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vrf_route_leaking.sh (14794B)


      1#!/bin/bash
      2# SPDX-License-Identifier: GPL-2.0
      3#
      4# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved.
      5# Copyright (c) 2020 Michael Jeanson <mjeanson@efficios.com>. All rights reserved.
      6#
      7# Requires CONFIG_NET_VRF, CONFIG_VETH, CONFIG_BRIDGE and CONFIG_NET_NS.
      8#
      9#
     10# Symmetric routing topology
     11#
     12#                     blue         red
     13# +----+              .253 +----+ .253              +----+
     14# | h1 |-------------------| r1 |-------------------| h2 |
     15# +----+ .1                +----+                .2 +----+
     16#         172.16.1/24                  172.16.2/24
     17#    2001:db8:16:1/64                  2001:db8:16:2/64
     18#
     19#
     20# Route from h1 to h2 and back goes through r1, incoming vrf blue has a route
     21# to the outgoing vrf red for the n2 network and red has a route back to n1.
     22# The red VRF interface has a MTU of 1400.
     23#
     24# The first test sends a ping with a ttl of 1 from h1 to h2 and parses the
     25# output of the command to check that a ttl expired error is received.
     26#
     27# The second test runs traceroute from h1 to h2 and parses the output to check
     28# for a hop on r1.
     29#
     30# The third test sends a ping with a packet size of 1450 from h1 to h2 and
     31# parses the output of the command to check that a fragmentation error is
     32# received.
     33#
     34#
     35# Asymmetric routing topology
     36#
     37# This topology represents a customer setup where the issue with icmp errors
     38# and VRF route leaking was initialy reported. The MTU test isn't done here
     39# because of the lack of a return route in the red VRF.
     40#
     41#                     blue         red
     42#                     .253 +----+ .253
     43#                     +----| r1 |----+
     44#                     |    +----+    |
     45# +----+              |              |              +----+
     46# | h1 |--------------+              +--------------| h2 |
     47# +----+ .1           |              |           .2 +----+
     48#         172.16.1/24 |    +----+    | 172.16.2/24
     49#    2001:db8:16:1/64 +----| r2 |----+ 2001:db8:16:2/64
     50#                     .254 +----+ .254
     51#
     52#
     53# Route from h1 to h2 goes through r1, incoming vrf blue has a route to the
     54# outgoing vrf red for the n2 network but red doesn't have a route back to n1.
     55# Route from h2 to h1 goes through r2.
     56#
     57# The objective is to check that the incoming vrf routing table is selected
     58# to send an ICMP error back to the source when the ttl of a packet reaches 1
     59# while it is forwarded between different vrfs.
     60
     61VERBOSE=0
     62PAUSE_ON_FAIL=no
     63DEFAULT_TTYPE=sym
     64
     65H1_N1=172.16.1.0/24
     66H1_N1_6=2001:db8:16:1::/64
     67
     68H1_N1_IP=172.16.1.1
     69R1_N1_IP=172.16.1.253
     70R2_N1_IP=172.16.1.254
     71
     72H1_N1_IP6=2001:db8:16:1::1
     73R1_N1_IP6=2001:db8:16:1::253
     74R2_N1_IP6=2001:db8:16:1::254
     75
     76H2_N2=172.16.2.0/24
     77H2_N2_6=2001:db8:16:2::/64
     78
     79H2_N2_IP=172.16.2.2
     80R1_N2_IP=172.16.2.253
     81R2_N2_IP=172.16.2.254
     82
     83H2_N2_IP6=2001:db8:16:2::2
     84R1_N2_IP6=2001:db8:16:2::253
     85R2_N2_IP6=2001:db8:16:2::254
     86
     87################################################################################
     88# helpers
     89
     90log_section()
     91{
     92	echo
     93	echo "###########################################################################"
     94	echo "$*"
     95	echo "###########################################################################"
     96	echo
     97}
     98
     99log_test()
    100{
    101	local rc=$1
    102	local expected=$2
    103	local msg="$3"
    104
    105	if [ "${rc}" -eq "${expected}" ]; then
    106		printf "TEST: %-60s  [ OK ]\n" "${msg}"
    107		nsuccess=$((nsuccess+1))
    108	else
    109		ret=1
    110		nfail=$((nfail+1))
    111		printf "TEST: %-60s  [FAIL]\n" "${msg}"
    112		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
    113			echo
    114			echo "hit enter to continue, 'q' to quit"
    115			read -r a
    116			[ "$a" = "q" ] && exit 1
    117		fi
    118	fi
    119}
    120
    121run_cmd()
    122{
    123	local cmd="$*"
    124	local out
    125	local rc
    126
    127	if [ "$VERBOSE" = "1" ]; then
    128		echo "COMMAND: $cmd"
    129	fi
    130
    131	# shellcheck disable=SC2086
    132	out=$(eval $cmd 2>&1)
    133	rc=$?
    134	if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
    135		echo "$out"
    136	fi
    137
    138	[ "$VERBOSE" = "1" ] && echo
    139
    140	return $rc
    141}
    142
    143run_cmd_grep()
    144{
    145	local grep_pattern="$1"
    146	shift
    147	local cmd="$*"
    148	local out
    149	local rc
    150
    151	if [ "$VERBOSE" = "1" ]; then
    152		echo "COMMAND: $cmd"
    153	fi
    154
    155	# shellcheck disable=SC2086
    156	out=$(eval $cmd 2>&1)
    157	if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
    158		echo "$out"
    159	fi
    160
    161	echo "$out" | grep -q "$grep_pattern"
    162	rc=$?
    163
    164	[ "$VERBOSE" = "1" ] && echo
    165
    166	return $rc
    167}
    168
    169################################################################################
    170# setup and teardown
    171
    172cleanup()
    173{
    174	local ns
    175
    176	for ns in h1 h2 r1 r2; do
    177		ip netns del $ns 2>/dev/null
    178	done
    179}
    180
    181setup_vrf()
    182{
    183	local ns=$1
    184
    185	ip -netns "${ns}" rule del pref 0
    186	ip -netns "${ns}" rule add pref 32765 from all lookup local
    187	ip -netns "${ns}" -6 rule del pref 0
    188	ip -netns "${ns}" -6 rule add pref 32765 from all lookup local
    189}
    190
    191create_vrf()
    192{
    193	local ns=$1
    194	local vrf=$2
    195	local table=$3
    196
    197	ip -netns "${ns}" link add "${vrf}" type vrf table "${table}"
    198	ip -netns "${ns}" link set "${vrf}" up
    199	ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192
    200	ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192
    201
    202	ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}"
    203	ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad
    204}
    205
    206setup_sym()
    207{
    208	local ns
    209
    210	# make sure we are starting with a clean slate
    211	cleanup
    212
    213	#
    214	# create nodes as namespaces
    215	#
    216	for ns in h1 h2 r1; do
    217		ip netns add $ns
    218		ip -netns $ns link set lo up
    219
    220		case "${ns}" in
    221		h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
    222		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
    223			;;
    224		r1)    ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
    225		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
    226		esac
    227	done
    228
    229	#
    230	# create interconnects
    231	#
    232	ip -netns h1 link add eth0 type veth peer name r1h1
    233	ip -netns h1 link set r1h1 netns r1 name eth0 up
    234
    235	ip -netns h2 link add eth0 type veth peer name r1h2
    236	ip -netns h2 link set r1h2 netns r1 name eth1 up
    237
    238	#
    239	# h1
    240	#
    241	ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24
    242	ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
    243	ip -netns h1 link set eth0 up
    244
    245	# h1 to h2 via r1
    246	ip -netns h1    route add ${H2_N2} via ${R1_N1_IP} dev eth0
    247	ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
    248
    249	#
    250	# h2
    251	#
    252	ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
    253	ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
    254	ip -netns h2 link set eth0 up
    255
    256	# h2 to h1 via r1
    257	ip -netns h2 route add default via ${R1_N2_IP} dev eth0
    258	ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0
    259
    260	#
    261	# r1
    262	#
    263	setup_vrf r1
    264	create_vrf r1 blue 1101
    265	create_vrf r1 red 1102
    266	ip -netns r1 link set mtu 1400 dev eth1
    267	ip -netns r1 link set eth0 vrf blue up
    268	ip -netns r1 link set eth1 vrf red up
    269	ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
    270	ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
    271	ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
    272	ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
    273
    274	# Route leak from blue to red
    275	ip -netns r1 route add vrf blue ${H2_N2} dev red
    276	ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
    277
    278	# Route leak from red to blue
    279	ip -netns r1 route add vrf red ${H1_N1} dev blue
    280	ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue
    281
    282
    283	# Wait for ip config to settle
    284	sleep 2
    285}
    286
    287setup_asym()
    288{
    289	local ns
    290
    291	# make sure we are starting with a clean slate
    292	cleanup
    293
    294	#
    295	# create nodes as namespaces
    296	#
    297	for ns in h1 h2 r1 r2; do
    298		ip netns add $ns
    299		ip -netns $ns link set lo up
    300
    301		case "${ns}" in
    302		h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
    303		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
    304			;;
    305		r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
    306		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
    307		esac
    308	done
    309
    310	#
    311	# create interconnects
    312	#
    313	ip -netns h1 link add eth0 type veth peer name r1h1
    314	ip -netns h1 link set r1h1 netns r1 name eth0 up
    315
    316	ip -netns h1 link add eth1 type veth peer name r2h1
    317	ip -netns h1 link set r2h1 netns r2 name eth0 up
    318
    319	ip -netns h2 link add eth0 type veth peer name r1h2
    320	ip -netns h2 link set r1h2 netns r1 name eth1 up
    321
    322	ip -netns h2 link add eth1 type veth peer name r2h2
    323	ip -netns h2 link set r2h2 netns r2 name eth1 up
    324
    325	#
    326	# h1
    327	#
    328	ip -netns h1 link add br0 type bridge
    329	ip -netns h1 link set br0 up
    330	ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
    331	ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
    332	ip -netns h1 link set eth0 master br0 up
    333	ip -netns h1 link set eth1 master br0 up
    334
    335	# h1 to h2 via r1
    336	ip -netns h1    route add ${H2_N2} via ${R1_N1_IP} dev br0
    337	ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
    338
    339	#
    340	# h2
    341	#
    342	ip -netns h2 link add br0 type bridge
    343	ip -netns h2 link set br0 up
    344	ip -netns h2 addr add dev br0 ${H2_N2_IP}/24
    345	ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
    346	ip -netns h2 link set eth0 master br0 up
    347	ip -netns h2 link set eth1 master br0 up
    348
    349	# h2 to h1 via r2
    350	ip -netns h2 route add default via ${R2_N2_IP} dev br0
    351	ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0
    352
    353	#
    354	# r1
    355	#
    356	setup_vrf r1
    357	create_vrf r1 blue 1101
    358	create_vrf r1 red 1102
    359	ip -netns r1 link set mtu 1400 dev eth1
    360	ip -netns r1 link set eth0 vrf blue up
    361	ip -netns r1 link set eth1 vrf red up
    362	ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
    363	ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
    364	ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
    365	ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
    366
    367	# Route leak from blue to red
    368	ip -netns r1 route add vrf blue ${H2_N2} dev red
    369	ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
    370
    371	# No route leak from red to blue
    372
    373	#
    374	# r2
    375	#
    376	ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
    377	ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
    378	ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24
    379	ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
    380
    381	# Wait for ip config to settle
    382	sleep 2
    383}
    384
    385check_connectivity()
    386{
    387	ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
    388	log_test $? 0 "Basic IPv4 connectivity"
    389	return $?
    390}
    391
    392check_connectivity6()
    393{
    394	ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
    395	log_test $? 0 "Basic IPv6 connectivity"
    396	return $?
    397}
    398
    399check_traceroute()
    400{
    401	if [ ! -x "$(command -v traceroute)" ]; then
    402		echo "SKIP: Could not run IPV4 test without traceroute"
    403		return 1
    404	fi
    405}
    406
    407check_traceroute6()
    408{
    409	if [ ! -x "$(command -v traceroute6)" ]; then
    410		echo "SKIP: Could not run IPV6 test without traceroute6"
    411		return 1
    412	fi
    413}
    414
    415ipv4_traceroute()
    416{
    417	local ttype="$1"
    418
    419	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    420
    421	log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute"
    422
    423	check_traceroute || return
    424
    425	setup_"$ttype"
    426
    427	check_connectivity || return
    428
    429	run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP}
    430	log_test $? 0 "Traceroute reports a hop on r1"
    431}
    432
    433ipv4_traceroute_asym()
    434{
    435	ipv4_traceroute asym
    436}
    437
    438ipv6_traceroute()
    439{
    440	local ttype="$1"
    441
    442	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    443
    444	log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute"
    445
    446	check_traceroute6 || return
    447
    448	setup_"$ttype"
    449
    450	check_connectivity6 || return
    451
    452	run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6}
    453	log_test $? 0 "Traceroute6 reports a hop on r1"
    454}
    455
    456ipv6_traceroute_asym()
    457{
    458	ipv6_traceroute asym
    459}
    460
    461ipv4_ping_ttl()
    462{
    463	local ttype="$1"
    464
    465	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    466
    467	log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping"
    468
    469	setup_"$ttype"
    470
    471	check_connectivity || return
    472
    473	run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP}
    474	log_test $? 0 "Ping received ICMP ttl exceeded"
    475}
    476
    477ipv4_ping_ttl_asym()
    478{
    479	ipv4_ping_ttl asym
    480}
    481
    482ipv4_ping_frag()
    483{
    484	local ttype="$1"
    485
    486	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    487
    488	log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping"
    489
    490	setup_"$ttype"
    491
    492	check_connectivity || return
    493
    494	run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
    495	log_test $? 0 "Ping received ICMP Frag needed"
    496}
    497
    498ipv4_ping_frag_asym()
    499{
    500	ipv4_ping_frag asym
    501}
    502
    503ipv6_ping_ttl()
    504{
    505	local ttype="$1"
    506
    507	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    508
    509	log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping"
    510
    511	setup_"$ttype"
    512
    513	check_connectivity6 || return
    514
    515	run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
    516	log_test $? 0 "Ping received ICMP Hop limit"
    517}
    518
    519ipv6_ping_ttl_asym()
    520{
    521	ipv6_ping_ttl asym
    522}
    523
    524ipv6_ping_frag()
    525{
    526	local ttype="$1"
    527
    528	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
    529
    530	log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping"
    531
    532	setup_"$ttype"
    533
    534	check_connectivity6 || return
    535
    536	run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
    537	log_test $? 0 "Ping received ICMP Packet too big"
    538}
    539
    540ipv6_ping_frag_asym()
    541{
    542	ipv6_ping_frag asym
    543}
    544
    545################################################################################
    546# usage
    547
    548usage()
    549{
    550        cat <<EOF
    551usage: ${0##*/} OPTS
    552
    553	-4          Run IPv4 tests only
    554	-6          Run IPv6 tests only
    555        -t TEST     Run only TEST
    556	-p          Pause on fail
    557	-v          verbose mode (show commands and output)
    558EOF
    559}
    560
    561################################################################################
    562# main
    563
    564# Some systems don't have a ping6 binary anymore
    565command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping)
    566
    567TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym"
    568TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_frag ipv6_ping_ttl_asym ipv6_traceroute_asym"
    569
    570ret=0
    571nsuccess=0
    572nfail=0
    573
    574while getopts :46t:pvh o
    575do
    576	case $o in
    577		4) TESTS=ipv4;;
    578		6) TESTS=ipv6;;
    579		t) TESTS=$OPTARG;;
    580		p) PAUSE_ON_FAIL=yes;;
    581		v) VERBOSE=1;;
    582		h) usage; exit 0;;
    583		*) usage; exit 1;;
    584	esac
    585done
    586
    587#
    588# show user test config
    589#
    590if [ -z "$TESTS" ]; then
    591        TESTS="$TESTS_IPV4 $TESTS_IPV6"
    592elif [ "$TESTS" = "ipv4" ]; then
    593        TESTS="$TESTS_IPV4"
    594elif [ "$TESTS" = "ipv6" ]; then
    595        TESTS="$TESTS_IPV6"
    596fi
    597
    598for t in $TESTS
    599do
    600	case $t in
    601	ipv4_ping_ttl|ping)              ipv4_ping_ttl;;&
    602	ipv4_ping_ttl_asym|ping)         ipv4_ping_ttl_asym;;&
    603	ipv4_traceroute|traceroute)      ipv4_traceroute;;&
    604	ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
    605	ipv4_ping_frag|ping)             ipv4_ping_frag;;&
    606
    607	ipv6_ping_ttl|ping)              ipv6_ping_ttl;;&
    608	ipv6_ping_ttl_asym|ping)         ipv6_ping_ttl_asym;;&
    609	ipv6_traceroute|traceroute)      ipv6_traceroute;;&
    610	ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
    611	ipv6_ping_frag|ping)             ipv6_ping_frag;;&
    612
    613	# setup namespaces and config, but do not run any tests
    614	setup_sym|setup)                 setup_sym; exit 0;;
    615	setup_asym)                      setup_asym; exit 0;;
    616
    617	help)                       echo "Test names: $TESTS"; exit 0;;
    618	esac
    619done
    620
    621cleanup
    622
    623printf "\nTests passed: %3d\n" ${nsuccess}
    624printf "Tests failed: %3d\n"   ${nfail}
    625
    626exit $ret