162306a36Sopenharmony_ci#!/bin/bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# This script tests the below topology:
762306a36Sopenharmony_ci#
862306a36Sopenharmony_ci# ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐
962306a36Sopenharmony_ci# │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │
1062306a36Sopenharmony_ci# │                     │   │                                  │   │                     │
1162306a36Sopenharmony_ci# │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│
1262306a36Sopenharmony_ci# ││  wg0   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg0   ││
1362306a36Sopenharmony_ci# │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│
1462306a36Sopenharmony_ci# ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││
1562306a36Sopenharmony_ci# ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││
1662306a36Sopenharmony_ci# │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│
1762306a36Sopenharmony_ci# └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘
1862306a36Sopenharmony_ci#                           └──────────────────────────────────┘
1962306a36Sopenharmony_ci#
2062306a36Sopenharmony_ci# After the topology is prepared we run a series of TCP/UDP iperf3 tests between the
2162306a36Sopenharmony_ci# wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0
2262306a36Sopenharmony_ci# interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further
2362306a36Sopenharmony_ci# details on how this is accomplished.
2462306a36Sopenharmony_ciset -e
2562306a36Sopenharmony_cishopt -s extglob
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciexec 3>&1
2862306a36Sopenharmony_ciexport LANG=C
2962306a36Sopenharmony_ciexport WG_HIDE_KEYS=never
3062306a36Sopenharmony_ciNPROC=( /sys/devices/system/cpu/cpu+([0-9]) ); NPROC=${#NPROC[@]}
3162306a36Sopenharmony_cinetns0="wg-test-$$-0"
3262306a36Sopenharmony_cinetns1="wg-test-$$-1"
3362306a36Sopenharmony_cinetns2="wg-test-$$-2"
3462306a36Sopenharmony_cipretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
3562306a36Sopenharmony_cipp() { pretty "" "$*"; "$@"; }
3662306a36Sopenharmony_cimaybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
3762306a36Sopenharmony_cin0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
3862306a36Sopenharmony_cin1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
3962306a36Sopenharmony_cin2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
4062306a36Sopenharmony_ciip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
4162306a36Sopenharmony_ciip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
4262306a36Sopenharmony_ciip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
4362306a36Sopenharmony_cisleep() { read -t "$1" -N 1 || true; }
4462306a36Sopenharmony_ciwaitiperf() { pretty "${1//*-}" "wait for iperf:${3:-5201} pid $2"; while [[ $(ss -N "$1" -tlpH "sport = ${3:-5201}") != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; }
4562306a36Sopenharmony_ciwaitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
4662306a36Sopenharmony_ciwaitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; }
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cicleanup() {
4962306a36Sopenharmony_ci	set +e
5062306a36Sopenharmony_ci	exec 2>/dev/null
5162306a36Sopenharmony_ci	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
5262306a36Sopenharmony_ci	ip0 link del dev wg0
5362306a36Sopenharmony_ci	ip0 link del dev wg1
5462306a36Sopenharmony_ci	ip1 link del dev wg0
5562306a36Sopenharmony_ci	ip1 link del dev wg1
5662306a36Sopenharmony_ci	ip2 link del dev wg0
5762306a36Sopenharmony_ci	ip2 link del dev wg1
5862306a36Sopenharmony_ci	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
5962306a36Sopenharmony_ci	[[ -n $to_kill ]] && kill $to_kill
6062306a36Sopenharmony_ci	pp ip netns del $netns1
6162306a36Sopenharmony_ci	pp ip netns del $netns2
6262306a36Sopenharmony_ci	pp ip netns del $netns0
6362306a36Sopenharmony_ci	exit
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciorig_message_cost="$(< /proc/sys/net/core/message_cost)"
6762306a36Sopenharmony_citrap cleanup EXIT
6862306a36Sopenharmony_ciprintf 0 > /proc/sys/net/core/message_cost
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciip netns del $netns0 2>/dev/null || true
7162306a36Sopenharmony_ciip netns del $netns1 2>/dev/null || true
7262306a36Sopenharmony_ciip netns del $netns2 2>/dev/null || true
7362306a36Sopenharmony_cipp ip netns add $netns0
7462306a36Sopenharmony_cipp ip netns add $netns1
7562306a36Sopenharmony_cipp ip netns add $netns2
7662306a36Sopenharmony_ciip0 link set up dev lo
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciip0 link add dev wg0 type wireguard
7962306a36Sopenharmony_ciip0 link set wg0 netns $netns1
8062306a36Sopenharmony_ciip0 link add dev wg0 type wireguard
8162306a36Sopenharmony_ciip0 link set wg0 netns $netns2
8262306a36Sopenharmony_cikey1="$(pp wg genkey)"
8362306a36Sopenharmony_cikey2="$(pp wg genkey)"
8462306a36Sopenharmony_cikey3="$(pp wg genkey)"
8562306a36Sopenharmony_cikey4="$(pp wg genkey)"
8662306a36Sopenharmony_cipub1="$(pp wg pubkey <<<"$key1")"
8762306a36Sopenharmony_cipub2="$(pp wg pubkey <<<"$key2")"
8862306a36Sopenharmony_cipub3="$(pp wg pubkey <<<"$key3")"
8962306a36Sopenharmony_cipub4="$(pp wg pubkey <<<"$key4")"
9062306a36Sopenharmony_cipsk="$(pp wg genpsk)"
9162306a36Sopenharmony_ci[[ -n $key1 && -n $key2 && -n $psk ]]
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciconfigure_peers() {
9462306a36Sopenharmony_ci	ip1 addr add 192.168.241.1/24 dev wg0
9562306a36Sopenharmony_ci	ip1 addr add fd00::1/112 dev wg0
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ip2 addr add 192.168.241.2/24 dev wg0
9862306a36Sopenharmony_ci	ip2 addr add fd00::2/112 dev wg0
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	n1 wg set wg0 \
10162306a36Sopenharmony_ci		private-key <(echo "$key1") \
10262306a36Sopenharmony_ci		listen-port 1 \
10362306a36Sopenharmony_ci		peer "$pub2" \
10462306a36Sopenharmony_ci			preshared-key <(echo "$psk") \
10562306a36Sopenharmony_ci			allowed-ips 192.168.241.2/32,fd00::2/128
10662306a36Sopenharmony_ci	n2 wg set wg0 \
10762306a36Sopenharmony_ci		private-key <(echo "$key2") \
10862306a36Sopenharmony_ci		listen-port 2 \
10962306a36Sopenharmony_ci		peer "$pub1" \
11062306a36Sopenharmony_ci			preshared-key <(echo "$psk") \
11162306a36Sopenharmony_ci			allowed-ips 192.168.241.1/32,fd00::1/128
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ip1 link set up dev wg0
11462306a36Sopenharmony_ci	ip2 link set up dev wg0
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ciconfigure_peers
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_citests() {
11962306a36Sopenharmony_ci	# Ping over IPv4
12062306a36Sopenharmony_ci	n2 ping -c 10 -f -W 1 192.168.241.1
12162306a36Sopenharmony_ci	n1 ping -c 10 -f -W 1 192.168.241.2
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	# Ping over IPv6
12462306a36Sopenharmony_ci	n2 ping6 -c 10 -f -W 1 fd00::1
12562306a36Sopenharmony_ci	n1 ping6 -c 10 -f -W 1 fd00::2
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	# TCP over IPv4
12862306a36Sopenharmony_ci	n2 iperf3 -s -1 -B 192.168.241.2 &
12962306a36Sopenharmony_ci	waitiperf $netns2 $!
13062306a36Sopenharmony_ci	n1 iperf3 -Z -t 3 -c 192.168.241.2
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	# TCP over IPv6
13362306a36Sopenharmony_ci	n1 iperf3 -s -1 -B fd00::1 &
13462306a36Sopenharmony_ci	waitiperf $netns1 $!
13562306a36Sopenharmony_ci	n2 iperf3 -Z -t 3 -c fd00::1
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	# UDP over IPv4
13862306a36Sopenharmony_ci	n1 iperf3 -s -1 -B 192.168.241.1 &
13962306a36Sopenharmony_ci	waitiperf $netns1 $!
14062306a36Sopenharmony_ci	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	# UDP over IPv6
14362306a36Sopenharmony_ci	n2 iperf3 -s -1 -B fd00::2 &
14462306a36Sopenharmony_ci	waitiperf $netns2 $!
14562306a36Sopenharmony_ci	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	# TCP over IPv4, in parallel
14862306a36Sopenharmony_ci	local pids=( ) i
14962306a36Sopenharmony_ci	for ((i=0; i < NPROC; ++i)) do
15062306a36Sopenharmony_ci		n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 &
15162306a36Sopenharmony_ci		pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i ))
15262306a36Sopenharmony_ci	done
15362306a36Sopenharmony_ci	for ((i=0; i < NPROC; ++i)) do
15462306a36Sopenharmony_ci		n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
15562306a36Sopenharmony_ci	done
15662306a36Sopenharmony_ci	wait "${pids[@]}"
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
16062306a36Sopenharmony_cibig_mtu=$(( 34816 - 1500 + $orig_mtu ))
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci# Test using IPv4 as outer transport
16362306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
16462306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
16562306a36Sopenharmony_ci# Before calling tests, we first make sure that the stats counters and timestamper are working
16662306a36Sopenharmony_cin2 ping -c 10 -f -W 1 192.168.241.1
16762306a36Sopenharmony_ci{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
16862306a36Sopenharmony_ci(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
16962306a36Sopenharmony_ci{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
17062306a36Sopenharmony_ci(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
17162306a36Sopenharmony_ciread _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
17262306a36Sopenharmony_ci(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
17362306a36Sopenharmony_ciread _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
17462306a36Sopenharmony_ci(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
17562306a36Sopenharmony_ciread _ timestamp < <(n1 wg show wg0 latest-handshakes)
17662306a36Sopenharmony_ci(( timestamp != 0 ))
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_citests
17962306a36Sopenharmony_ciip1 link set wg0 mtu $big_mtu
18062306a36Sopenharmony_ciip2 link set wg0 mtu $big_mtu
18162306a36Sopenharmony_citests
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciip1 link set wg0 mtu $orig_mtu
18462306a36Sopenharmony_ciip2 link set wg0 mtu $orig_mtu
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci# Test using IPv6 as outer transport
18762306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint [::1]:2
18862306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint [::1]:1
18962306a36Sopenharmony_citests
19062306a36Sopenharmony_ciip1 link set wg0 mtu $big_mtu
19162306a36Sopenharmony_ciip2 link set wg0 mtu $big_mtu
19262306a36Sopenharmony_citests
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci# Test that route MTUs work with the padding
19562306a36Sopenharmony_ciip1 link set wg0 mtu 1300
19662306a36Sopenharmony_ciip2 link set wg0 mtu 1300
19762306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
19862306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
19962306a36Sopenharmony_cin0 iptables -A INPUT -m length --length 1360 -j DROP
20062306a36Sopenharmony_cin1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
20162306a36Sopenharmony_cin2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
20262306a36Sopenharmony_cin2 ping -c 1 -W 1 -s 1269 192.168.241.1
20362306a36Sopenharmony_cin2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
20462306a36Sopenharmony_cin1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
20562306a36Sopenharmony_cin0 iptables -F INPUT
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciip1 link set wg0 mtu $orig_mtu
20862306a36Sopenharmony_ciip2 link set wg0 mtu $orig_mtu
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci# Test using IPv4 that roaming works
21162306a36Sopenharmony_ciip0 -4 addr del 127.0.0.1/8 dev lo
21262306a36Sopenharmony_ciip0 -4 addr add 127.212.121.99/8 dev lo
21362306a36Sopenharmony_cin1 wg set wg0 listen-port 9999
21462306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
21562306a36Sopenharmony_cin1 ping6 -W 1 -c 1 fd00::2
21662306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	127.212.121.99:9999" ]]
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci# Test using IPv6 that roaming works
21962306a36Sopenharmony_cin1 wg set wg0 listen-port 9998
22062306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint [::1]:2
22162306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
22262306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	[::1]:9998" ]]
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci# Test that crypto-RP filter works
22562306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
22662306a36Sopenharmony_ciexec 4< <(n1 ncat -l -u -p 1111)
22762306a36Sopenharmony_cincat_pid=$!
22862306a36Sopenharmony_ciwaitncatudp $netns1 $ncat_pid
22962306a36Sopenharmony_cin2 ncat -u 192.168.241.1 1111 <<<"X"
23062306a36Sopenharmony_ciread -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
23162306a36Sopenharmony_cikill $ncat_pid
23262306a36Sopenharmony_cimore_specific_key="$(pp wg genkey | pp wg pubkey)"
23362306a36Sopenharmony_cin1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
23462306a36Sopenharmony_cin2 wg set wg0 listen-port 9997
23562306a36Sopenharmony_ciexec 4< <(n1 ncat -l -u -p 1111)
23662306a36Sopenharmony_cincat_pid=$!
23762306a36Sopenharmony_ciwaitncatudp $netns1 $ncat_pid
23862306a36Sopenharmony_cin2 ncat -u 192.168.241.1 1111 <<<"X"
23962306a36Sopenharmony_ci! read -r -N 1 -t 1 out <&4 || false
24062306a36Sopenharmony_cikill $ncat_pid
24162306a36Sopenharmony_cin1 wg set wg0 peer "$more_specific_key" remove
24262306a36Sopenharmony_ci[[ $(n1 wg show wg0 endpoints) == "$pub2	[::1]:9997" ]]
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci# Test that we can change private keys keys and immediately handshake
24562306a36Sopenharmony_cin1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips 192.168.241.2/32 endpoint 127.0.0.1:2
24662306a36Sopenharmony_cin2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
24762306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
24862306a36Sopenharmony_cin1 wg set wg0 private-key <(echo "$key3")
24962306a36Sopenharmony_cin2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
25062306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
25162306a36Sopenharmony_cin2 wg set wg0 peer "$pub3" remove
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci# Test that we can route wg through wg
25462306a36Sopenharmony_ciip1 addr flush dev wg0
25562306a36Sopenharmony_ciip2 addr flush dev wg0
25662306a36Sopenharmony_ciip1 addr add fd00::5:1/112 dev wg0
25762306a36Sopenharmony_ciip2 addr add fd00::5:2/112 dev wg0
25862306a36Sopenharmony_cin1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips fd00::5:2/128 endpoint 127.0.0.1:2
25962306a36Sopenharmony_cin2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips fd00::5:1/128 endpoint 127.212.121.99:9998
26062306a36Sopenharmony_ciip1 link add wg1 type wireguard
26162306a36Sopenharmony_ciip2 link add wg1 type wireguard
26262306a36Sopenharmony_ciip1 addr add 192.168.241.1/24 dev wg1
26362306a36Sopenharmony_ciip1 addr add fd00::1/112 dev wg1
26462306a36Sopenharmony_ciip2 addr add 192.168.241.2/24 dev wg1
26562306a36Sopenharmony_ciip2 addr add fd00::2/112 dev wg1
26662306a36Sopenharmony_ciip1 link set mtu 1340 up dev wg1
26762306a36Sopenharmony_ciip2 link set mtu 1340 up dev wg1
26862306a36Sopenharmony_cin1 wg set wg1 listen-port 5 private-key <(echo "$key3") peer "$pub4" allowed-ips 192.168.241.2/32,fd00::2/128 endpoint [fd00::5:2]:5
26962306a36Sopenharmony_cin2 wg set wg1 listen-port 5 private-key <(echo "$key4") peer "$pub3" allowed-ips 192.168.241.1/32,fd00::1/128 endpoint [fd00::5:1]:5
27062306a36Sopenharmony_citests
27162306a36Sopenharmony_ci# Try to set up a routing loop between the two namespaces
27262306a36Sopenharmony_ciip1 link set netns $netns0 dev wg1
27362306a36Sopenharmony_ciip0 addr add 192.168.241.1/24 dev wg1
27462306a36Sopenharmony_ciip0 link set up dev wg1
27562306a36Sopenharmony_cin0 ping -W 1 -c 1 192.168.241.2
27662306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
27762306a36Sopenharmony_ciip2 link del wg0
27862306a36Sopenharmony_ciip2 link del wg1
27962306a36Sopenharmony_ciread _ _ tx_bytes_before < <(n0 wg show wg1 transfer)
28062306a36Sopenharmony_ci! n0 ping -W 1 -c 10 -f 192.168.241.2 || false
28162306a36Sopenharmony_cisleep 1
28262306a36Sopenharmony_ciread _ _ tx_bytes_after < <(n0 wg show wg1 transfer)
28362306a36Sopenharmony_ciif ! (( tx_bytes_after - tx_bytes_before < 70000 )); then
28462306a36Sopenharmony_ci	errstart=$'\x1b[37m\x1b[41m\x1b[1m'
28562306a36Sopenharmony_ci	errend=$'\x1b[0m'
28662306a36Sopenharmony_ci	echo "${errstart}                                                ${errend}"
28762306a36Sopenharmony_ci	echo "${errstart}                   E  R  R  O  R                ${errend}"
28862306a36Sopenharmony_ci	echo "${errstart}                                                ${errend}"
28962306a36Sopenharmony_ci	echo "${errstart} This architecture does not do the right thing  ${errend}"
29062306a36Sopenharmony_ci	echo "${errstart} with cross-namespace routing loops. This test  ${errend}"
29162306a36Sopenharmony_ci	echo "${errstart} has thus technically failed but, as this issue ${errend}"
29262306a36Sopenharmony_ci	echo "${errstart} is as yet unsolved, these tests will continue  ${errend}"
29362306a36Sopenharmony_ci	echo "${errstart} onward. :(                                     ${errend}"
29462306a36Sopenharmony_ci	echo "${errstart}                                                ${errend}"
29562306a36Sopenharmony_cifi
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ciip0 link del wg1
29862306a36Sopenharmony_ciip1 link del wg0
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci# Test using NAT. We now change the topology to this:
30162306a36Sopenharmony_ci# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
30262306a36Sopenharmony_ci# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
30362306a36Sopenharmony_ci# │                                        │    │                                                │     │                                        │
30462306a36Sopenharmony_ci# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
30562306a36Sopenharmony_ci# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
30662306a36Sopenharmony_ci# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
30762306a36Sopenharmony_ci# │  │192.168.241.1/24│  │192.168.1.100/24││    │    │192.168.1.1/24  │    │10.0.0.1/24        │ │     │  │10.0.0.100/24   │ │192.168.241.2/24│ │
30862306a36Sopenharmony_ci# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
30962306a36Sopenharmony_ci# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
31062306a36Sopenharmony_ci# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ciip1 link add dev wg0 type wireguard
31362306a36Sopenharmony_ciip2 link add dev wg0 type wireguard
31462306a36Sopenharmony_ciconfigure_peers
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ciip0 link add vethrc type veth peer name vethc
31762306a36Sopenharmony_ciip0 link add vethrs type veth peer name veths
31862306a36Sopenharmony_ciip0 link set vethc netns $netns1
31962306a36Sopenharmony_ciip0 link set veths netns $netns2
32062306a36Sopenharmony_ciip0 link set vethrc up
32162306a36Sopenharmony_ciip0 link set vethrs up
32262306a36Sopenharmony_ciip0 addr add 192.168.1.1/24 dev vethrc
32362306a36Sopenharmony_ciip0 addr add 10.0.0.1/24 dev vethrs
32462306a36Sopenharmony_ciip1 addr add 192.168.1.100/24 dev vethc
32562306a36Sopenharmony_ciip1 link set vethc up
32662306a36Sopenharmony_ciip1 route add default via 192.168.1.1
32762306a36Sopenharmony_ciip2 addr add 10.0.0.100/24 dev veths
32862306a36Sopenharmony_ciip2 link set veths up
32962306a36Sopenharmony_ciwaitiface $netns0 vethrc
33062306a36Sopenharmony_ciwaitiface $netns0 vethrs
33162306a36Sopenharmony_ciwaitiface $netns1 vethc
33262306a36Sopenharmony_ciwaitiface $netns2 veths
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cin0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
33562306a36Sopenharmony_cin0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
33662306a36Sopenharmony_cin0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
33762306a36Sopenharmony_cin0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
34062306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
34162306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
34262306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
34362306a36Sopenharmony_ci# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
34462306a36Sopenharmony_cipp sleep 3
34562306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
34662306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" persistent-keepalive 0
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci# Test that sk_bound_dev_if works
34962306a36Sopenharmony_cin1 ping -I wg0 -c 1 -W 1 192.168.241.2
35062306a36Sopenharmony_ci# What about when the mark changes and the packet must be rerouted?
35162306a36Sopenharmony_cin1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
35262306a36Sopenharmony_cin1 ping -c 1 -W 1 192.168.241.2 # First the boring case
35362306a36Sopenharmony_cin1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
35462306a36Sopenharmony_cin1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci# Test that onion routing works, even when it loops
35762306a36Sopenharmony_cin1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
35862306a36Sopenharmony_ciip1 addr add 192.168.242.1/24 dev wg0
35962306a36Sopenharmony_ciip2 link add wg1 type wireguard
36062306a36Sopenharmony_ciip2 addr add 192.168.242.2/24 dev wg1
36162306a36Sopenharmony_cin2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
36262306a36Sopenharmony_ciip2 link set wg1 up
36362306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.242.2
36462306a36Sopenharmony_ciip2 link del wg1
36562306a36Sopenharmony_cin1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
36662306a36Sopenharmony_ci! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
36762306a36Sopenharmony_cin1 wg set wg0 peer "$pub3" remove
36862306a36Sopenharmony_ciip1 addr del 192.168.242.1/24 dev wg0
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
37162306a36Sopenharmony_ciip1 -6 addr add fc00::9/96 dev vethc
37262306a36Sopenharmony_ciip1 -6 route add default via fc00::1
37362306a36Sopenharmony_ciip2 -4 addr add 192.168.99.7/32 dev wg0
37462306a36Sopenharmony_ciip2 -6 addr add abab::1111/128 dev wg0
37562306a36Sopenharmony_cin1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
37662306a36Sopenharmony_ciip1 -6 route add default dev wg0 table 51820
37762306a36Sopenharmony_ciip1 -6 rule add not fwmark 51820 table 51820
37862306a36Sopenharmony_ciip1 -6 rule add table main suppress_prefixlength 0
37962306a36Sopenharmony_ciip1 -4 route add default dev wg0 table 51820
38062306a36Sopenharmony_ciip1 -4 rule add not fwmark 51820 table 51820
38162306a36Sopenharmony_ciip1 -4 rule add table main suppress_prefixlength 0
38262306a36Sopenharmony_cin1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter'
38362306a36Sopenharmony_ci# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
38462306a36Sopenharmony_cin1 ping -W 1 -c 100 -f 192.168.99.7
38562306a36Sopenharmony_cin1 ping -W 1 -c 100 -f abab::1111
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
38862306a36Sopenharmony_cin2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
38962306a36Sopenharmony_cin0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
39062306a36Sopenharmony_cin2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
39162306a36Sopenharmony_ciip0 -4 route add 192.168.241.1 via 10.0.0.100
39262306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" remove
39362306a36Sopenharmony_ci[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cin0 iptables -t nat -F
39662306a36Sopenharmony_cin0 iptables -t filter -F
39762306a36Sopenharmony_cin2 iptables -t nat -F
39862306a36Sopenharmony_ciip0 link del vethrc
39962306a36Sopenharmony_ciip0 link del vethrs
40062306a36Sopenharmony_ciip1 link del wg0
40162306a36Sopenharmony_ciip2 link del wg0
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci# Test that saddr routing is sticky but not too sticky, changing to this topology:
40462306a36Sopenharmony_ci# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
40562306a36Sopenharmony_ci# │             $ns1 namespace             │    │             $ns2 namespace             │
40662306a36Sopenharmony_ci# │                                        │    │                                        │
40762306a36Sopenharmony_ci# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
40862306a36Sopenharmony_ci# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
40962306a36Sopenharmony_ci# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
41062306a36Sopenharmony_ci# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
41162306a36Sopenharmony_ci# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
41262306a36Sopenharmony_ci# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
41362306a36Sopenharmony_ci# └────────────────────────────────────────┘    └────────────────────────────────────────┘
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ciip1 link add dev wg0 type wireguard
41662306a36Sopenharmony_ciip2 link add dev wg0 type wireguard
41762306a36Sopenharmony_ciconfigure_peers
41862306a36Sopenharmony_ciip1 link add veth1 type veth peer name veth2
41962306a36Sopenharmony_ciip1 link set veth2 netns $netns2
42062306a36Sopenharmony_cin1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
42162306a36Sopenharmony_cin2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
42262306a36Sopenharmony_cin1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
42362306a36Sopenharmony_cin2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
42462306a36Sopenharmony_cin1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
42762306a36Sopenharmony_ciip1 addr add 10.0.0.1/24 dev veth1
42862306a36Sopenharmony_ciip1 addr add fd00:aa::1/96 dev veth1
42962306a36Sopenharmony_ciip2 addr add 10.0.0.2/24 dev veth2
43062306a36Sopenharmony_ciip2 addr add fd00:aa::2/96 dev veth2
43162306a36Sopenharmony_ciip1 link set veth1 up
43262306a36Sopenharmony_ciip2 link set veth2 up
43362306a36Sopenharmony_ciwaitiface $netns1 veth1
43462306a36Sopenharmony_ciwaitiface $netns2 veth2
43562306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
43662306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
43762306a36Sopenharmony_ciip1 addr add 10.0.0.10/24 dev veth1
43862306a36Sopenharmony_ciip1 addr del 10.0.0.1/24 dev veth1
43962306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
44062306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
44162306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
44262306a36Sopenharmony_ciip1 addr add fd00:aa::10/96 dev veth1
44362306a36Sopenharmony_ciip1 addr del fd00:aa::1/96 dev veth1
44462306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci# Now we show that we can successfully do reply to sender routing
44762306a36Sopenharmony_ciip1 link set veth1 down
44862306a36Sopenharmony_ciip2 link set veth2 down
44962306a36Sopenharmony_ciip1 addr flush dev veth1
45062306a36Sopenharmony_ciip2 addr flush dev veth2
45162306a36Sopenharmony_ciip1 addr add 10.0.0.1/24 dev veth1
45262306a36Sopenharmony_ciip1 addr add 10.0.0.2/24 dev veth1
45362306a36Sopenharmony_ciip1 addr add fd00:aa::1/96 dev veth1
45462306a36Sopenharmony_ciip1 addr add fd00:aa::2/96 dev veth1
45562306a36Sopenharmony_ciip2 addr add 10.0.0.3/24 dev veth2
45662306a36Sopenharmony_ciip2 addr add fd00:aa::3/96 dev veth2
45762306a36Sopenharmony_ciip1 link set veth1 up
45862306a36Sopenharmony_ciip2 link set veth2 up
45962306a36Sopenharmony_ciwaitiface $netns1 veth1
46062306a36Sopenharmony_ciwaitiface $netns2 veth2
46162306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
46262306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
46362306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
46462306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
46562306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
46662306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
46762306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
46862306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
46962306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
47062306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
47162306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
47262306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci# What happens if the inbound destination address belongs to a different interface as the default route?
47562306a36Sopenharmony_ciip1 link add dummy0 type dummy
47662306a36Sopenharmony_ciip1 addr add 10.50.0.1/24 dev dummy0
47762306a36Sopenharmony_ciip1 link set dummy0 up
47862306a36Sopenharmony_ciip2 route add 10.50.0.0/24 dev veth2
47962306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
48062306a36Sopenharmony_cin2 ping -W 1 -c 1 192.168.241.1
48162306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ciip1 link del dummy0
48462306a36Sopenharmony_ciip1 addr flush dev veth1
48562306a36Sopenharmony_ciip2 addr flush dev veth2
48662306a36Sopenharmony_ciip1 route flush dev veth1
48762306a36Sopenharmony_ciip2 route flush dev veth2
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci# Now we see what happens if another interface route takes precedence over an ongoing one
49062306a36Sopenharmony_ciip1 link add veth3 type veth peer name veth4
49162306a36Sopenharmony_ciip1 link set veth4 netns $netns2
49262306a36Sopenharmony_ciip1 addr add 10.0.0.1/24 dev veth1
49362306a36Sopenharmony_ciip2 addr add 10.0.0.2/24 dev veth2
49462306a36Sopenharmony_ciip1 addr add 10.0.0.3/24 dev veth3
49562306a36Sopenharmony_ciip1 link set veth1 up
49662306a36Sopenharmony_ciip2 link set veth2 up
49762306a36Sopenharmony_ciip1 link set veth3 up
49862306a36Sopenharmony_ciip2 link set veth4 up
49962306a36Sopenharmony_ciwaitiface $netns1 veth1
50062306a36Sopenharmony_ciwaitiface $netns2 veth2
50162306a36Sopenharmony_ciwaitiface $netns1 veth3
50262306a36Sopenharmony_ciwaitiface $netns2 veth4
50362306a36Sopenharmony_ciip1 route flush dev veth1
50462306a36Sopenharmony_ciip1 route flush dev veth3
50562306a36Sopenharmony_ciip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
50662306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
50762306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
50862306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
50962306a36Sopenharmony_ciip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
51062306a36Sopenharmony_cin1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
51162306a36Sopenharmony_cin2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
51262306a36Sopenharmony_cin1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
51362306a36Sopenharmony_cin2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
51462306a36Sopenharmony_cin1 ping -W 1 -c 1 192.168.241.2
51562306a36Sopenharmony_ci[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ciip1 link del dev veth3
51862306a36Sopenharmony_ciip1 link del dev wg0
51962306a36Sopenharmony_ciip2 link del dev wg0
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci# Make sure persistent keep alives are sent when an adapter comes up
52262306a36Sopenharmony_ciip1 link add dev wg0 type wireguard
52362306a36Sopenharmony_cin1 wg set wg0 private-key <(echo "$key1") peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
52462306a36Sopenharmony_ciread _ _ tx_bytes < <(n1 wg show wg0 transfer)
52562306a36Sopenharmony_ci[[ $tx_bytes -eq 0 ]]
52662306a36Sopenharmony_ciip1 link set dev wg0 up
52762306a36Sopenharmony_ciread _ _ tx_bytes < <(n1 wg show wg0 transfer)
52862306a36Sopenharmony_ci[[ $tx_bytes -gt 0 ]]
52962306a36Sopenharmony_ciip1 link del dev wg0
53062306a36Sopenharmony_ci# This should also happen even if the private key is set later
53162306a36Sopenharmony_ciip1 link add dev wg0 type wireguard
53262306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
53362306a36Sopenharmony_ciread _ _ tx_bytes < <(n1 wg show wg0 transfer)
53462306a36Sopenharmony_ci[[ $tx_bytes -eq 0 ]]
53562306a36Sopenharmony_ciip1 link set dev wg0 up
53662306a36Sopenharmony_ciread _ _ tx_bytes < <(n1 wg show wg0 transfer)
53762306a36Sopenharmony_ci[[ $tx_bytes -eq 0 ]]
53862306a36Sopenharmony_cin1 wg set wg0 private-key <(echo "$key1")
53962306a36Sopenharmony_ciread _ _ tx_bytes < <(n1 wg show wg0 transfer)
54062306a36Sopenharmony_ci[[ $tx_bytes -gt 0 ]]
54162306a36Sopenharmony_ciip1 link del dev veth1
54262306a36Sopenharmony_ciip1 link del dev wg0
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci# We test that Netlink/IPC is working properly by doing things that usually cause split responses
54562306a36Sopenharmony_ciip0 link add dev wg0 type wireguard
54662306a36Sopenharmony_ciconfig=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
54762306a36Sopenharmony_cifor a in {1..255}; do
54862306a36Sopenharmony_ci	for b in {0..255}; do
54962306a36Sopenharmony_ci		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
55062306a36Sopenharmony_ci	done
55162306a36Sopenharmony_cidone
55262306a36Sopenharmony_cin0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
55362306a36Sopenharmony_cii=0
55462306a36Sopenharmony_cifor ip in $(n0 wg show wg0 allowed-ips); do
55562306a36Sopenharmony_ci	((++i))
55662306a36Sopenharmony_cidone
55762306a36Sopenharmony_ci((i == 255*256*2+1))
55862306a36Sopenharmony_ciip0 link del wg0
55962306a36Sopenharmony_ciip0 link add dev wg0 type wireguard
56062306a36Sopenharmony_ciconfig=( "[Interface]" "PrivateKey=$(wg genkey)" )
56162306a36Sopenharmony_cifor a in {1..40}; do
56262306a36Sopenharmony_ci	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
56362306a36Sopenharmony_ci	for b in {1..52}; do
56462306a36Sopenharmony_ci		config+=( "AllowedIPs=$a.$b.0.0/16" )
56562306a36Sopenharmony_ci	done
56662306a36Sopenharmony_cidone
56762306a36Sopenharmony_cin0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
56862306a36Sopenharmony_cii=0
56962306a36Sopenharmony_ciwhile read -r line; do
57062306a36Sopenharmony_ci	j=0
57162306a36Sopenharmony_ci	for ip in $line; do
57262306a36Sopenharmony_ci		((++j))
57362306a36Sopenharmony_ci	done
57462306a36Sopenharmony_ci	((j == 53))
57562306a36Sopenharmony_ci	((++i))
57662306a36Sopenharmony_cidone < <(n0 wg show wg0 allowed-ips)
57762306a36Sopenharmony_ci((i == 40))
57862306a36Sopenharmony_ciip0 link del wg0
57962306a36Sopenharmony_ciip0 link add wg0 type wireguard
58062306a36Sopenharmony_ciconfig=( )
58162306a36Sopenharmony_cifor i in {1..29}; do
58262306a36Sopenharmony_ci	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
58362306a36Sopenharmony_cidone
58462306a36Sopenharmony_ciconfig+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
58562306a36Sopenharmony_cin0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
58662306a36Sopenharmony_cin0 wg showconf wg0 > /dev/null
58762306a36Sopenharmony_ciip0 link del wg0
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ciallowedips=( )
59062306a36Sopenharmony_cifor i in {1..197}; do
59162306a36Sopenharmony_ci        allowedips+=( abcd::$i )
59262306a36Sopenharmony_cidone
59362306a36Sopenharmony_cisaved_ifs="$IFS"
59462306a36Sopenharmony_ciIFS=,
59562306a36Sopenharmony_ciallowedips="${allowedips[*]}"
59662306a36Sopenharmony_ciIFS="$saved_ifs"
59762306a36Sopenharmony_ciip0 link add wg0 type wireguard
59862306a36Sopenharmony_cin0 wg set wg0 peer "$pub1"
59962306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	read -r pub allowedips
60262306a36Sopenharmony_ci	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
60362306a36Sopenharmony_ci	read -r pub allowedips
60462306a36Sopenharmony_ci	[[ $pub == "$pub2" ]]
60562306a36Sopenharmony_ci	i=0
60662306a36Sopenharmony_ci	for _ in $allowedips; do
60762306a36Sopenharmony_ci		((++i))
60862306a36Sopenharmony_ci	done
60962306a36Sopenharmony_ci	((i == 197))
61062306a36Sopenharmony_ci} < <(n0 wg show wg0 allowed-ips)
61162306a36Sopenharmony_ciip0 link del wg0
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci! n0 wg show doesnotexist || false
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ciip0 link add wg0 type wireguard
61662306a36Sopenharmony_cin0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
61762306a36Sopenharmony_ci[[ $(n0 wg show wg0 private-key) == "$key1" ]]
61862306a36Sopenharmony_ci[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
61962306a36Sopenharmony_cin0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
62062306a36Sopenharmony_ci[[ $(n0 wg show wg0 private-key) == "(none)" ]]
62162306a36Sopenharmony_ci[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
62262306a36Sopenharmony_cin0 wg set wg0 peer "$pub2"
62362306a36Sopenharmony_cin0 wg set wg0 private-key <(echo "$key2")
62462306a36Sopenharmony_ci[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
62562306a36Sopenharmony_ci[[ -z $(n0 wg show wg0 peers) ]]
62662306a36Sopenharmony_cin0 wg set wg0 peer "$pub2"
62762306a36Sopenharmony_ci[[ -z $(n0 wg show wg0 peers) ]]
62862306a36Sopenharmony_cin0 wg set wg0 private-key <(echo "$key1")
62962306a36Sopenharmony_cin0 wg set wg0 peer "$pub2"
63062306a36Sopenharmony_ci[[ $(n0 wg show wg0 peers) == "$pub2" ]]
63162306a36Sopenharmony_cin0 wg set wg0 private-key <(echo "/${key1:1}")
63262306a36Sopenharmony_ci[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
63362306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0,10.0.0.0/8,100.0.0.0/10,172.16.0.0/12,192.168.0.0/16
63462306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
63562306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
63662306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" allowed-ips ::/0
63762306a36Sopenharmony_cin0 wg set wg0 peer "$pub2" remove
63862306a36Sopenharmony_cifor low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
63962306a36Sopenharmony_ci	n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
64062306a36Sopenharmony_cidone
64162306a36Sopenharmony_ci[[ -n $(n0 wg show wg0 peers) ]]
64262306a36Sopenharmony_ciexec 4< <(n0 ncat -l -u -p 1111)
64362306a36Sopenharmony_cincat_pid=$!
64462306a36Sopenharmony_ciwaitncatudp $netns0 $ncat_pid
64562306a36Sopenharmony_ciip0 link set wg0 up
64662306a36Sopenharmony_ci! read -r -n 1 -t 2 <&4 || false
64762306a36Sopenharmony_cikill $ncat_pid
64862306a36Sopenharmony_ciip0 link del wg0
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci# Ensure that dst_cache references don't outlive netns lifetime
65162306a36Sopenharmony_ciip1 link add dev wg0 type wireguard
65262306a36Sopenharmony_ciip2 link add dev wg0 type wireguard
65362306a36Sopenharmony_ciconfigure_peers
65462306a36Sopenharmony_ciip1 link add veth1 type veth peer name veth2
65562306a36Sopenharmony_ciip1 link set veth2 netns $netns2
65662306a36Sopenharmony_ciip1 addr add fd00:aa::1/64 dev veth1
65762306a36Sopenharmony_ciip2 addr add fd00:aa::2/64 dev veth2
65862306a36Sopenharmony_ciip1 link set veth1 up
65962306a36Sopenharmony_ciip2 link set veth2 up
66062306a36Sopenharmony_ciwaitiface $netns1 veth1
66162306a36Sopenharmony_ciwaitiface $netns2 veth2
66262306a36Sopenharmony_ciip1 -6 route add default dev veth1 via fd00:aa::2
66362306a36Sopenharmony_ciip2 -6 route add default dev veth2 via fd00:aa::1
66462306a36Sopenharmony_cin1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
66562306a36Sopenharmony_cin2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
66662306a36Sopenharmony_cin1 ping6 -c 1 fd00::2
66762306a36Sopenharmony_cipp ip netns delete $netns1
66862306a36Sopenharmony_cipp ip netns delete $netns2
66962306a36Sopenharmony_cipp ip netns add $netns1
67062306a36Sopenharmony_cipp ip netns add $netns2
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci# Ensure there aren't circular reference loops
67362306a36Sopenharmony_ciip1 link add wg1 type wireguard
67462306a36Sopenharmony_ciip2 link add wg2 type wireguard
67562306a36Sopenharmony_ciip1 link set wg1 netns $netns2
67662306a36Sopenharmony_ciip2 link set wg2 netns $netns1
67762306a36Sopenharmony_cipp ip netns delete $netns1
67862306a36Sopenharmony_cipp ip netns delete $netns2
67962306a36Sopenharmony_cipp ip netns add $netns1
68062306a36Sopenharmony_cipp ip netns add $netns2
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cisleep 2 # Wait for cleanup and grace periods
68362306a36Sopenharmony_cideclare -A objects
68462306a36Sopenharmony_ciwhile read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
68562306a36Sopenharmony_ci	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
68662306a36Sopenharmony_ci	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
68762306a36Sopenharmony_cidone < /dev/kmsg
68862306a36Sopenharmony_cialldeleted=1
68962306a36Sopenharmony_cifor object in "${!objects[@]}"; do
69062306a36Sopenharmony_ci	if [[ ${objects["$object"]} != *createddestroyed && ${objects["$object"]} != *createdcreateddestroyeddestroyed ]]; then
69162306a36Sopenharmony_ci		echo "Error: $object: merely ${objects["$object"]}" >&3
69262306a36Sopenharmony_ci		alldeleted=0
69362306a36Sopenharmony_ci	fi
69462306a36Sopenharmony_cidone
69562306a36Sopenharmony_ci[[ $alldeleted -eq 1 ]]
69662306a36Sopenharmony_cipretty "" "Objects that were created were also destroyed."
697