xref: /linux/tools/testing/selftests/wireguard/netns.sh (revision c34e9ab9a612ee8b18273398ef75c207b01f516d)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5#
6# This script tests the below topology:
7#
8# ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐
9# │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │
10# │                     │   │                                  │   │                     │
11# │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│
12# ││  wg0   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg0   ││
13# │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│
14# ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││
15# ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││
16# │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│
17# └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘
18#                           └──────────────────────────────────┘
19#
20# After the topology is prepared we run a series of TCP/UDP iperf3 tests between the
21# wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0
22# interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further
23# details on how this is accomplished.
24set -e
25shopt -s extglob
26
27exec 3>&1
28export LANG=C
29export WG_HIDE_KEYS=never
30NPROC=( /sys/devices/system/cpu/cpu+([0-9]) ); NPROC=${#NPROC[@]}
31netns0="wg-test-$$-0"
32netns1="wg-test-$$-1"
33netns2="wg-test-$$-2"
34pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
35pp() { pretty "" "$*"; "$@"; }
36maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
37n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
38n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
39n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
40ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
41ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
42ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
43sleep() { read -t "$1" -N 1 || true; }
44waitiperf() { 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; }
45waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
46waitiface() { 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;"; }
47
48cleanup() {
49	set +e
50	exec 2>/dev/null
51	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
52	ip0 link del dev wg0
53	ip0 link del dev wg1
54	ip1 link del dev wg0
55	ip1 link del dev wg1
56	ip2 link del dev wg0
57	ip2 link del dev wg1
58	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
59	[[ -n $to_kill ]] && kill $to_kill
60	pp ip netns del $netns1
61	pp ip netns del $netns2
62	pp ip netns del $netns0
63	exit
64}
65
66orig_message_cost="$(< /proc/sys/net/core/message_cost)"
67trap cleanup EXIT
68printf 0 > /proc/sys/net/core/message_cost
69
70ip netns del $netns0 2>/dev/null || true
71ip netns del $netns1 2>/dev/null || true
72ip netns del $netns2 2>/dev/null || true
73pp ip netns add $netns0
74pp ip netns add $netns1
75pp ip netns add $netns2
76ip0 link set up dev lo
77
78ip0 link add dev wg0 type wireguard
79ip0 link set wg0 netns $netns1
80ip0 link add dev wg0 type wireguard
81ip0 link set wg0 netns $netns2
82key1="$(pp wg genkey)"
83key2="$(pp wg genkey)"
84key3="$(pp wg genkey)"
85key4="$(pp wg genkey)"
86pub1="$(pp wg pubkey <<<"$key1")"
87pub2="$(pp wg pubkey <<<"$key2")"
88pub3="$(pp wg pubkey <<<"$key3")"
89pub4="$(pp wg pubkey <<<"$key4")"
90psk="$(pp wg genpsk)"
91[[ -n $key1 && -n $key2 && -n $psk ]]
92
93configure_peers() {
94	ip1 addr add 192.168.241.1/24 dev wg0
95	ip1 addr add fd00::1/112 dev wg0
96
97	ip2 addr add 192.168.241.2/24 dev wg0
98	ip2 addr add fd00::2/112 dev wg0
99
100	n1 wg set wg0 \
101		private-key <(echo "$key1") \
102		listen-port 1 \
103		peer "$pub2" \
104			preshared-key <(echo "$psk") \
105			allowed-ips 192.168.241.2/32,fd00::2/128
106	n2 wg set wg0 \
107		private-key <(echo "$key2") \
108		listen-port 2 \
109		peer "$pub1" \
110			preshared-key <(echo "$psk") \
111			allowed-ips 192.168.241.1/32,fd00::1/128
112
113	ip1 link set up dev wg0
114	ip2 link set up dev wg0
115}
116configure_peers
117
118tests() {
119	# Ping over IPv4
120	n2 ping -c 10 -f -W 1 192.168.241.1
121	n1 ping -c 10 -f -W 1 192.168.241.2
122
123	# Ping over IPv6
124	n2 ping6 -c 10 -f -W 1 fd00::1
125	n1 ping6 -c 10 -f -W 1 fd00::2
126
127	# TCP over IPv4
128	n2 iperf3 -s -1 -B 192.168.241.2 &
129	waitiperf $netns2 $!
130	n1 iperf3 -Z -t 3 -c 192.168.241.2
131
132	# TCP over IPv6
133	n1 iperf3 -s -1 -B fd00::1 &
134	waitiperf $netns1 $!
135	n2 iperf3 -Z -t 3 -c fd00::1
136
137	# UDP over IPv4
138	n1 iperf3 -s -1 -B 192.168.241.1 &
139	waitiperf $netns1 $!
140	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
141
142	# UDP over IPv6
143	n2 iperf3 -s -1 -B fd00::2 &
144	waitiperf $netns2 $!
145	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
146
147	# TCP over IPv4, in parallel
148	local pids=( ) i
149	for ((i=0; i < NPROC; ++i)) do
150		n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 &
151		pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i ))
152	done
153	for ((i=0; i < NPROC; ++i)) do
154		n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
155	done
156	wait "${pids[@]}"
157}
158
159[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
160big_mtu=$(( 34816 - 1500 + $orig_mtu ))
161
162# Test using IPv4 as outer transport
163n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
164n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
165# Before calling tests, we first make sure that the stats counters and timestamper are working
166n2 ping -c 10 -f -W 1 192.168.241.1
167{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
168(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
169{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
170(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
171read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
172(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
173read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
174(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
175read _ timestamp < <(n1 wg show wg0 latest-handshakes)
176(( timestamp != 0 ))
177
178tests
179ip1 link set wg0 mtu $big_mtu
180ip2 link set wg0 mtu $big_mtu
181tests
182
183ip1 link set wg0 mtu $orig_mtu
184ip2 link set wg0 mtu $orig_mtu
185
186# Test using IPv6 as outer transport
187n1 wg set wg0 peer "$pub2" endpoint [::1]:2
188n2 wg set wg0 peer "$pub1" endpoint [::1]:1
189tests
190ip1 link set wg0 mtu $big_mtu
191ip2 link set wg0 mtu $big_mtu
192tests
193
194# Test that route MTUs work with the padding
195ip1 link set wg0 mtu 1300
196ip2 link set wg0 mtu 1300
197n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
198n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
199n0 iptables -A INPUT -m length --length 1360 -j DROP
200n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
201n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
202n2 ping -c 1 -W 1 -s 1269 192.168.241.1
203n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
204n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
205n0 iptables -F INPUT
206
207ip1 link set wg0 mtu $orig_mtu
208ip2 link set wg0 mtu $orig_mtu
209
210# Test using IPv4 that roaming works
211ip0 -4 addr del 127.0.0.1/8 dev lo
212ip0 -4 addr add 127.212.121.99/8 dev lo
213n1 wg set wg0 listen-port 9999
214n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
215n1 ping6 -W 1 -c 1 fd00::2
216[[ $(n2 wg show wg0 endpoints) == "$pub1	127.212.121.99:9999" ]]
217
218# Test using IPv6 that roaming works
219n1 wg set wg0 listen-port 9998
220n1 wg set wg0 peer "$pub2" endpoint [::1]:2
221n1 ping -W 1 -c 1 192.168.241.2
222[[ $(n2 wg show wg0 endpoints) == "$pub1	[::1]:9998" ]]
223
224# Test that crypto-RP filter works
225n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
226exec 4< <(n1 ncat -l -u -p 1111)
227ncat_pid=$!
228waitncatudp $netns1 $ncat_pid
229n2 ncat -u 192.168.241.1 1111 <<<"X"
230read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
231kill $ncat_pid
232more_specific_key="$(pp wg genkey | pp wg pubkey)"
233n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
234n2 wg set wg0 listen-port 9997
235exec 4< <(n1 ncat -l -u -p 1111)
236ncat_pid=$!
237waitncatudp $netns1 $ncat_pid
238n2 ncat -u 192.168.241.1 1111 <<<"X"
239! read -r -N 1 -t 1 out <&4 || false
240kill $ncat_pid
241n1 wg set wg0 peer "$more_specific_key" remove
242[[ $(n1 wg show wg0 endpoints) == "$pub2	[::1]:9997" ]]
243
244# Test that we can change private keys keys and immediately handshake
245n1 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
246n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
247n1 ping -W 1 -c 1 192.168.241.2
248n1 wg set wg0 private-key <(echo "$key3")
249n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
250n1 ping -W 1 -c 1 192.168.241.2
251n2 wg set wg0 peer "$pub3" remove
252
253# Test that we can route wg through wg
254ip1 addr flush dev wg0
255ip2 addr flush dev wg0
256ip1 addr add fd00::5:1/112 dev wg0
257ip2 addr add fd00::5:2/112 dev wg0
258n1 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
259n2 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
260ip1 link add wg1 type wireguard
261ip2 link add wg1 type wireguard
262ip1 addr add 192.168.241.1/24 dev wg1
263ip1 addr add fd00::1/112 dev wg1
264ip2 addr add 192.168.241.2/24 dev wg1
265ip2 addr add fd00::2/112 dev wg1
266ip1 link set mtu 1340 up dev wg1
267ip2 link set mtu 1340 up dev wg1
268n1 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
269n2 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
270tests
271# Try to set up a routing loop between the two namespaces
272ip1 link set netns $netns0 dev wg1
273ip0 addr add 192.168.241.1/24 dev wg1
274ip0 link set up dev wg1
275n0 ping -W 1 -c 1 192.168.241.2
276n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
277ip2 link del wg0
278ip2 link del wg1
279read _ _ tx_bytes_before < <(n0 wg show wg1 transfer)
280! n0 ping -W 1 -c 10 -f 192.168.241.2 || false
281sleep 1
282read _ _ tx_bytes_after < <(n0 wg show wg1 transfer)
283if ! (( tx_bytes_after - tx_bytes_before < 70000 )); then
284	errstart=$'\x1b[37m\x1b[41m\x1b[1m'
285	errend=$'\x1b[0m'
286	echo "${errstart}                                                ${errend}"
287	echo "${errstart}                   E  R  R  O  R                ${errend}"
288	echo "${errstart}                                                ${errend}"
289	echo "${errstart} This architecture does not do the right thing  ${errend}"
290	echo "${errstart} with cross-namespace routing loops. This test  ${errend}"
291	echo "${errstart} has thus technically failed but, as this issue ${errend}"
292	echo "${errstart} is as yet unsolved, these tests will continue  ${errend}"
293	echo "${errstart} onward. :(                                     ${errend}"
294	echo "${errstart}                                                ${errend}"
295fi
296
297ip0 link del wg1
298ip1 link del wg0
299
300# Test using NAT. We now change the topology to this:
301# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
302# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
303# │                                        │    │                                                │     │                                        │
304# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
305# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
306# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
307# │  │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│ │
308# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
309# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
310# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
311
312ip1 link add dev wg0 type wireguard
313ip2 link add dev wg0 type wireguard
314configure_peers
315
316ip0 link add vethrc type veth peer name vethc
317ip0 link add vethrs type veth peer name veths
318ip0 link set vethc netns $netns1
319ip0 link set veths netns $netns2
320ip0 link set vethrc up
321ip0 link set vethrs up
322ip0 addr add 192.168.1.1/24 dev vethrc
323ip0 addr add 10.0.0.1/24 dev vethrs
324ip1 addr add 192.168.1.100/24 dev vethc
325ip1 link set vethc up
326ip1 route add default via 192.168.1.1
327ip2 addr add 10.0.0.100/24 dev veths
328ip2 link set veths up
329waitiface $netns0 vethrc
330waitiface $netns0 vethrs
331waitiface $netns1 vethc
332waitiface $netns2 veths
333
334n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
335[[ -e /proc/sys/net/netfilter/nf_conntrack_udp_timeout ]] || modprobe nf_conntrack
336n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
337n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
338n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
339
340n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
341n1 ping -W 1 -c 1 192.168.241.2
342n2 ping -W 1 -c 1 192.168.241.1
343[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
344# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
345pp sleep 3
346n2 ping -W 1 -c 1 192.168.241.1
347n1 wg set wg0 peer "$pub2" persistent-keepalive 0
348
349# Test that sk_bound_dev_if works
350n1 ping -I wg0 -c 1 -W 1 192.168.241.2
351# What about when the mark changes and the packet must be rerouted?
352n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
353n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
354n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
355n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
356
357# Test that onion routing works, even when it loops
358n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
359ip1 addr add 192.168.242.1/24 dev wg0
360ip2 link add wg1 type wireguard
361ip2 addr add 192.168.242.2/24 dev wg1
362n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
363ip2 link set wg1 up
364n1 ping -W 1 -c 1 192.168.242.2
365ip2 link del wg1
366n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
367! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
368n1 wg set wg0 peer "$pub3" remove
369ip1 addr del 192.168.242.1/24 dev wg0
370
371# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
372ip1 -6 addr add fc00::9/96 dev vethc
373ip1 -6 route add default via fc00::1
374ip2 -4 addr add 192.168.99.7/32 dev wg0
375ip2 -6 addr add abab::1111/128 dev wg0
376n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
377ip1 -6 route add default dev wg0 table 51820
378ip1 -6 rule add not fwmark 51820 table 51820
379ip1 -6 rule add table main suppress_prefixlength 0
380ip1 -4 route add default dev wg0 table 51820
381ip1 -4 rule add not fwmark 51820 table 51820
382ip1 -4 rule add table main suppress_prefixlength 0
383n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter'
384# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
385n1 ping -W 1 -c 100 -f 192.168.99.7
386n1 ping -W 1 -c 100 -f abab::1111
387
388# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
389n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
390n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
391n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
392ip0 -4 route add 192.168.241.1 via 10.0.0.100
393n2 wg set wg0 peer "$pub1" remove
394[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
395
396n0 iptables -t nat -F
397n0 iptables -t filter -F
398n2 iptables -t nat -F
399ip0 link del vethrc
400ip0 link del vethrs
401ip1 link del wg0
402ip2 link del wg0
403
404# Test that saddr routing is sticky but not too sticky, changing to this topology:
405# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
406# │             $ns1 namespace             │    │             $ns2 namespace             │
407# │                                        │    │                                        │
408# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
409# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
410# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
411# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
412# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
413# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
414# └────────────────────────────────────────┘    └────────────────────────────────────────┘
415
416ip1 link add dev wg0 type wireguard
417ip2 link add dev wg0 type wireguard
418configure_peers
419ip1 link add veth1 type veth peer name veth2
420ip1 link set veth2 netns $netns2
421n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
422n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
423n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
424n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
425n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
426
427# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
428ip1 addr add 10.0.0.1/24 dev veth1
429ip1 addr add fd00:aa::1/96 dev veth1
430ip2 addr add 10.0.0.2/24 dev veth2
431ip2 addr add fd00:aa::2/96 dev veth2
432ip1 link set veth1 up
433ip2 link set veth2 up
434waitiface $netns1 veth1
435waitiface $netns2 veth2
436n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
437n1 ping -W 1 -c 1 192.168.241.2
438ip1 addr add 10.0.0.10/24 dev veth1
439ip1 addr del 10.0.0.1/24 dev veth1
440n1 ping -W 1 -c 1 192.168.241.2
441n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
442n1 ping -W 1 -c 1 192.168.241.2
443ip1 addr add fd00:aa::10/96 dev veth1
444ip1 addr del fd00:aa::1/96 dev veth1
445n1 ping -W 1 -c 1 192.168.241.2
446
447# Now we show that we can successfully do reply to sender routing
448ip1 link set veth1 down
449ip2 link set veth2 down
450ip1 addr flush dev veth1
451ip2 addr flush dev veth2
452ip1 addr add 10.0.0.1/24 dev veth1
453ip1 addr add 10.0.0.2/24 dev veth1
454ip1 addr add fd00:aa::1/96 dev veth1
455ip1 addr add fd00:aa::2/96 dev veth1
456ip2 addr add 10.0.0.3/24 dev veth2
457ip2 addr add fd00:aa::3/96 dev veth2
458ip1 link set veth1 up
459ip2 link set veth2 up
460waitiface $netns1 veth1
461waitiface $netns2 veth2
462n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
463n2 ping -W 1 -c 1 192.168.241.1
464[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
465n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
466n2 ping -W 1 -c 1 192.168.241.1
467[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
468n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
469n2 ping -W 1 -c 1 192.168.241.1
470[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
471n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
472n2 ping -W 1 -c 1 192.168.241.1
473[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
474
475# What happens if the inbound destination address belongs to a different interface as the default route?
476ip1 link add dummy0 type dummy
477ip1 addr add 10.50.0.1/24 dev dummy0
478ip1 link set dummy0 up
479ip2 route add 10.50.0.0/24 dev veth2
480n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
481n2 ping -W 1 -c 1 192.168.241.1
482[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
483
484ip1 link del dummy0
485ip1 addr flush dev veth1
486ip2 addr flush dev veth2
487ip1 route flush dev veth1
488ip2 route flush dev veth2
489
490# Now we see what happens if another interface route takes precedence over an ongoing one
491ip1 link add veth3 type veth peer name veth4
492ip1 link set veth4 netns $netns2
493ip1 addr add 10.0.0.1/24 dev veth1
494ip2 addr add 10.0.0.2/24 dev veth2
495ip1 addr add 10.0.0.3/24 dev veth3
496ip1 link set veth1 up
497ip2 link set veth2 up
498ip1 link set veth3 up
499ip2 link set veth4 up
500waitiface $netns1 veth1
501waitiface $netns2 veth2
502waitiface $netns1 veth3
503waitiface $netns2 veth4
504ip1 route flush dev veth1
505ip1 route flush dev veth3
506ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
507n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
508n1 ping -W 1 -c 1 192.168.241.2
509[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
510ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
511n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
512n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
513n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
514n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
515n1 ping -W 1 -c 1 192.168.241.2
516[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
517
518ip1 link del dev veth3
519ip1 link del dev wg0
520ip2 link del dev wg0
521
522# Make sure persistent keep alives are sent when an adapter comes up
523ip1 link add dev wg0 type wireguard
524n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
525read _ _ tx_bytes < <(n1 wg show wg0 transfer)
526[[ $tx_bytes -eq 0 ]]
527ip1 link set dev wg0 up
528read _ _ tx_bytes < <(n1 wg show wg0 transfer)
529[[ $tx_bytes -gt 0 ]]
530ip1 link del dev wg0
531# This should also happen even if the private key is set later
532ip1 link add dev wg0 type wireguard
533n1 wg set wg0 peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
534read _ _ tx_bytes < <(n1 wg show wg0 transfer)
535[[ $tx_bytes -eq 0 ]]
536ip1 link set dev wg0 up
537read _ _ tx_bytes < <(n1 wg show wg0 transfer)
538[[ $tx_bytes -eq 0 ]]
539n1 wg set wg0 private-key <(echo "$key1")
540read _ _ tx_bytes < <(n1 wg show wg0 transfer)
541[[ $tx_bytes -gt 0 ]]
542ip1 link del dev veth1
543ip1 link del dev wg0
544
545# We test that Netlink/IPC is working properly by doing things that usually cause split responses
546ip0 link add dev wg0 type wireguard
547config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
548for a in {1..255}; do
549	for b in {0..255}; do
550		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
551	done
552done
553n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
554i=0
555for ip in $(n0 wg show wg0 allowed-ips); do
556	((++i))
557done
558((i == 255*256*2+1))
559ip0 link del wg0
560ip0 link add dev wg0 type wireguard
561config=( "[Interface]" "PrivateKey=$(wg genkey)" )
562for a in {1..40}; do
563	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
564	for b in {1..52}; do
565		config+=( "AllowedIPs=$a.$b.0.0/16" )
566	done
567done
568n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
569i=0
570while read -r line; do
571	j=0
572	for ip in $line; do
573		((++j))
574	done
575	((j == 53))
576	((++i))
577done < <(n0 wg show wg0 allowed-ips)
578((i == 40))
579ip0 link del wg0
580ip0 link add wg0 type wireguard
581config=( )
582for i in {1..29}; do
583	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
584done
585config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
586n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
587n0 wg showconf wg0 > /dev/null
588ip0 link del wg0
589
590allowedips=( )
591for i in {1..197}; do
592        allowedips+=( abcd::$i )
593done
594saved_ifs="$IFS"
595IFS=,
596allowedips="${allowedips[*]}"
597IFS="$saved_ifs"
598ip0 link add wg0 type wireguard
599n0 wg set wg0 peer "$pub1"
600n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
601{
602	read -r pub allowedips
603	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
604	read -r pub allowedips
605	[[ $pub == "$pub2" ]]
606	i=0
607	for _ in $allowedips; do
608		((++i))
609	done
610	((i == 197))
611} < <(n0 wg show wg0 allowed-ips)
612ip0 link del wg0
613
614! n0 wg show doesnotexist || false
615
616ip0 link add wg0 type wireguard
617n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
618[[ $(n0 wg show wg0 private-key) == "$key1" ]]
619[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
620n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
621[[ $(n0 wg show wg0 private-key) == "(none)" ]]
622[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
623n0 wg set wg0 peer "$pub2"
624n0 wg set wg0 private-key <(echo "$key2")
625[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
626[[ -z $(n0 wg show wg0 peers) ]]
627n0 wg set wg0 peer "$pub2"
628[[ -z $(n0 wg show wg0 peers) ]]
629n0 wg set wg0 private-key <(echo "$key1")
630n0 wg set wg0 peer "$pub2"
631[[ $(n0 wg show wg0 peers) == "$pub2" ]]
632n0 wg set wg0 private-key <(echo "/${key1:1}")
633[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
634n0 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
635n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
636n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
637n0 wg set wg0 peer "$pub2" allowed-ips ::/0
638n0 wg set wg0 peer "$pub2" remove
639for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
640	n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
641done
642[[ -n $(n0 wg show wg0 peers) ]]
643exec 4< <(n0 ncat -l -u -p 1111)
644ncat_pid=$!
645waitncatudp $netns0 $ncat_pid
646ip0 link set wg0 up
647! read -r -n 1 -t 2 <&4 || false
648kill $ncat_pid
649ip0 link del wg0
650
651# Ensure that dst_cache references don't outlive netns lifetime
652ip1 link add dev wg0 type wireguard
653ip2 link add dev wg0 type wireguard
654configure_peers
655ip1 link add veth1 type veth peer name veth2
656ip1 link set veth2 netns $netns2
657ip1 addr add fd00:aa::1/64 dev veth1
658ip2 addr add fd00:aa::2/64 dev veth2
659ip1 link set veth1 up
660ip2 link set veth2 up
661waitiface $netns1 veth1
662waitiface $netns2 veth2
663ip1 -6 route add default dev veth1 via fd00:aa::2
664ip2 -6 route add default dev veth2 via fd00:aa::1
665n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
666n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
667n1 ping6 -c 1 fd00::2
668pp ip netns delete $netns1
669pp ip netns delete $netns2
670pp ip netns add $netns1
671pp ip netns add $netns2
672
673# Ensure there aren't circular reference loops
674ip1 link add wg1 type wireguard
675ip2 link add wg2 type wireguard
676ip1 link set wg1 netns $netns2
677ip2 link set wg2 netns $netns1
678pp ip netns delete $netns1
679pp ip netns delete $netns2
680pp ip netns add $netns1
681pp ip netns add $netns2
682
683sleep 2 # Wait for cleanup and grace periods
684declare -A objects
685while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
686	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
687	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
688done < /dev/kmsg
689alldeleted=1
690for object in "${!objects[@]}"; do
691	if [[ ${objects["$object"]} != *createddestroyed && ${objects["$object"]} != *createdcreateddestroyeddestroyed ]]; then
692		echo "Error: $object: merely ${objects["$object"]}" >&3
693		alldeleted=0
694	fi
695done
696[[ $alldeleted -eq 1 ]]
697pretty "" "Objects that were created were also destroyed."
698