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
25
26exec 3>&1
27export LANG=C
28export WG_HIDE_KEYS=never
29netns0="wg-test-$$-0"
30netns1="wg-test-$$-1"
31netns2="wg-test-$$-2"
32pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
33pp() { pretty "" "$*"; "$@"; }
34maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
35n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
36n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
37n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
38ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
39ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
40ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
41sleep() { read -t "$1" -N 1 || true; }
42waitiperf() { 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; }
43waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
44waitiface() { 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;"; }
45
46cleanup() {
47	set +e
48	exec 2>/dev/null
49	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
50	ip0 link del dev wg0
51	ip0 link del dev wg1
52	ip1 link del dev wg0
53	ip1 link del dev wg1
54	ip2 link del dev wg0
55	ip2 link del dev wg1
56	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
57	[[ -n $to_kill ]] && kill $to_kill
58	pp ip netns del $netns1
59	pp ip netns del $netns2
60	pp ip netns del $netns0
61	exit
62}
63
64orig_message_cost="$(< /proc/sys/net/core/message_cost)"
65trap cleanup EXIT
66printf 0 > /proc/sys/net/core/message_cost
67
68ip netns del $netns0 2>/dev/null || true
69ip netns del $netns1 2>/dev/null || true
70ip netns del $netns2 2>/dev/null || true
71pp ip netns add $netns0
72pp ip netns add $netns1
73pp ip netns add $netns2
74ip0 link set up dev lo
75
76ip0 link add dev wg0 type wireguard
77ip0 link set wg0 netns $netns1
78ip0 link add dev wg0 type wireguard
79ip0 link set wg0 netns $netns2
80key1="$(pp wg genkey)"
81key2="$(pp wg genkey)"
82key3="$(pp wg genkey)"
83key4="$(pp wg genkey)"
84pub1="$(pp wg pubkey <<<"$key1")"
85pub2="$(pp wg pubkey <<<"$key2")"
86pub3="$(pp wg pubkey <<<"$key3")"
87pub4="$(pp wg pubkey <<<"$key4")"
88psk="$(pp wg genpsk)"
89[[ -n $key1 && -n $key2 && -n $psk ]]
90
91configure_peers() {
92	ip1 addr add 192.168.241.1/24 dev wg0
93	ip1 addr add fd00::1/112 dev wg0
94
95	ip2 addr add 192.168.241.2/24 dev wg0
96	ip2 addr add fd00::2/112 dev wg0
97
98	n1 wg set wg0 \
99		private-key <(echo "$key1") \
100		listen-port 1 \
101		peer "$pub2" \
102			preshared-key <(echo "$psk") \
103			allowed-ips 192.168.241.2/32,fd00::2/128
104	n2 wg set wg0 \
105		private-key <(echo "$key2") \
106		listen-port 2 \
107		peer "$pub1" \
108			preshared-key <(echo "$psk") \
109			allowed-ips 192.168.241.1/32,fd00::1/128
110
111	ip1 link set up dev wg0
112	ip2 link set up dev wg0
113}
114configure_peers
115
116tests() {
117	# Ping over IPv4
118	n2 ping -c 10 -f -W 1 192.168.241.1
119	n1 ping -c 10 -f -W 1 192.168.241.2
120
121	# Ping over IPv6
122	n2 ping6 -c 10 -f -W 1 fd00::1
123	n1 ping6 -c 10 -f -W 1 fd00::2
124
125	# TCP over IPv4
126	n2 iperf3 -s -1 -B 192.168.241.2 &
127	waitiperf $netns2 $!
128	n1 iperf3 -Z -t 3 -c 192.168.241.2
129
130	# TCP over IPv6
131	n1 iperf3 -s -1 -B fd00::1 &
132	waitiperf $netns1 $!
133	n2 iperf3 -Z -t 3 -c fd00::1
134
135	# UDP over IPv4
136	n1 iperf3 -s -1 -B 192.168.241.1 &
137	waitiperf $netns1 $!
138	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
139
140	# UDP over IPv6
141	n2 iperf3 -s -1 -B fd00::2 &
142	waitiperf $netns2 $!
143	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
144
145	# TCP over IPv4, in parallel
146	for max in 4 5 50; do
147		local pids=( )
148		for ((i=0; i < max; ++i)) do
149			n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 &
150			pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i ))
151		done
152		for ((i=0; i < max; ++i)) do
153			n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
154		done
155		wait "${pids[@]}"
156	done
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
279! n0 ping -W 1 -c 10 -f 192.168.241.2 || false # Should not crash kernel
280
281ip0 link del wg1
282ip1 link del wg0
283
284# Test using NAT. We now change the topology to this:
285# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
286# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
287# │                                        │    │                                                │     │                                        │
288# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
289# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
290# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
291# │  │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│ │
292# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
293# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
294# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
295
296ip1 link add dev wg0 type wireguard
297ip2 link add dev wg0 type wireguard
298configure_peers
299
300ip0 link add vethrc type veth peer name vethc
301ip0 link add vethrs type veth peer name veths
302ip0 link set vethc netns $netns1
303ip0 link set veths netns $netns2
304ip0 link set vethrc up
305ip0 link set vethrs up
306ip0 addr add 192.168.1.1/24 dev vethrc
307ip0 addr add 10.0.0.1/24 dev vethrs
308ip1 addr add 192.168.1.100/24 dev vethc
309ip1 link set vethc up
310ip1 route add default via 192.168.1.1
311ip2 addr add 10.0.0.100/24 dev veths
312ip2 link set veths up
313waitiface $netns0 vethrc
314waitiface $netns0 vethrs
315waitiface $netns1 vethc
316waitiface $netns2 veths
317
318n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
319n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
320n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
321n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
322
323n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
324n1 ping -W 1 -c 1 192.168.241.2
325n2 ping -W 1 -c 1 192.168.241.1
326[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
327# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
328pp sleep 3
329n2 ping -W 1 -c 1 192.168.241.1
330n1 wg set wg0 peer "$pub2" persistent-keepalive 0
331
332# Test that sk_bound_dev_if works
333n1 ping -I wg0 -c 1 -W 1 192.168.241.2
334# What about when the mark changes and the packet must be rerouted?
335n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
336n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
337n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
338n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
339
340# Test that onion routing works, even when it loops
341n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
342ip1 addr add 192.168.242.1/24 dev wg0
343ip2 link add wg1 type wireguard
344ip2 addr add 192.168.242.2/24 dev wg1
345n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
346ip2 link set wg1 up
347n1 ping -W 1 -c 1 192.168.242.2
348ip2 link del wg1
349n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
350! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
351n1 wg set wg0 peer "$pub3" remove
352ip1 addr del 192.168.242.1/24 dev wg0
353
354# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
355ip1 -6 addr add fc00::9/96 dev vethc
356ip1 -6 route add default via fc00::1
357ip2 -4 addr add 192.168.99.7/32 dev wg0
358ip2 -6 addr add abab::1111/128 dev wg0
359n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
360ip1 -6 route add default dev wg0 table 51820
361ip1 -6 rule add not fwmark 51820 table 51820
362ip1 -6 rule add table main suppress_prefixlength 0
363ip1 -4 route add default dev wg0 table 51820
364ip1 -4 rule add not fwmark 51820 table 51820
365ip1 -4 rule add table main suppress_prefixlength 0
366# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
367n1 ping -W 1 -c 100 -f 192.168.99.7
368n1 ping -W 1 -c 100 -f abab::1111
369
370# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
371n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
372n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
373n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
374ip0 -4 route add 192.168.241.1 via 10.0.0.100
375n2 wg set wg0 peer "$pub1" remove
376[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
377
378n0 iptables -t nat -F
379n0 iptables -t filter -F
380n2 iptables -t nat -F
381ip0 link del vethrc
382ip0 link del vethrs
383ip1 link del wg0
384ip2 link del wg0
385
386# Test that saddr routing is sticky but not too sticky, changing to this topology:
387# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
388# │             $ns1 namespace             │    │             $ns2 namespace             │
389# │                                        │    │                                        │
390# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
391# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
392# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
393# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
394# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
395# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
396# └────────────────────────────────────────┘    └────────────────────────────────────────┘
397
398ip1 link add dev wg0 type wireguard
399ip2 link add dev wg0 type wireguard
400configure_peers
401ip1 link add veth1 type veth peer name veth2
402ip1 link set veth2 netns $netns2
403n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
404n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
405n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
406n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
407n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
408
409# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
410ip1 addr add 10.0.0.1/24 dev veth1
411ip1 addr add fd00:aa::1/96 dev veth1
412ip2 addr add 10.0.0.2/24 dev veth2
413ip2 addr add fd00:aa::2/96 dev veth2
414ip1 link set veth1 up
415ip2 link set veth2 up
416waitiface $netns1 veth1
417waitiface $netns2 veth2
418n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
419n1 ping -W 1 -c 1 192.168.241.2
420ip1 addr add 10.0.0.10/24 dev veth1
421ip1 addr del 10.0.0.1/24 dev veth1
422n1 ping -W 1 -c 1 192.168.241.2
423n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
424n1 ping -W 1 -c 1 192.168.241.2
425ip1 addr add fd00:aa::10/96 dev veth1
426ip1 addr del fd00:aa::1/96 dev veth1
427n1 ping -W 1 -c 1 192.168.241.2
428
429# Now we show that we can successfully do reply to sender routing
430ip1 link set veth1 down
431ip2 link set veth2 down
432ip1 addr flush dev veth1
433ip2 addr flush dev veth2
434ip1 addr add 10.0.0.1/24 dev veth1
435ip1 addr add 10.0.0.2/24 dev veth1
436ip1 addr add fd00:aa::1/96 dev veth1
437ip1 addr add fd00:aa::2/96 dev veth1
438ip2 addr add 10.0.0.3/24 dev veth2
439ip2 addr add fd00:aa::3/96 dev veth2
440ip1 link set veth1 up
441ip2 link set veth2 up
442waitiface $netns1 veth1
443waitiface $netns2 veth2
444n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
445n2 ping -W 1 -c 1 192.168.241.1
446[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
447n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
448n2 ping -W 1 -c 1 192.168.241.1
449[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
450n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
451n2 ping -W 1 -c 1 192.168.241.1
452[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
453n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
454n2 ping -W 1 -c 1 192.168.241.1
455[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
456
457# What happens if the inbound destination address belongs to a different interface as the default route?
458ip1 link add dummy0 type dummy
459ip1 addr add 10.50.0.1/24 dev dummy0
460ip1 link set dummy0 up
461ip2 route add 10.50.0.0/24 dev veth2
462n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
463n2 ping -W 1 -c 1 192.168.241.1
464[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
465
466ip1 link del dummy0
467ip1 addr flush dev veth1
468ip2 addr flush dev veth2
469ip1 route flush dev veth1
470ip2 route flush dev veth2
471
472# Now we see what happens if another interface route takes precedence over an ongoing one
473ip1 link add veth3 type veth peer name veth4
474ip1 link set veth4 netns $netns2
475ip1 addr add 10.0.0.1/24 dev veth1
476ip2 addr add 10.0.0.2/24 dev veth2
477ip1 addr add 10.0.0.3/24 dev veth3
478ip1 link set veth1 up
479ip2 link set veth2 up
480ip1 link set veth3 up
481ip2 link set veth4 up
482waitiface $netns1 veth1
483waitiface $netns2 veth2
484waitiface $netns1 veth3
485waitiface $netns2 veth4
486ip1 route flush dev veth1
487ip1 route flush dev veth3
488ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
489n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
490n1 ping -W 1 -c 1 192.168.241.2
491[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
492ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
493n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
494n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
495n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
496n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
497n1 ping -W 1 -c 1 192.168.241.2
498[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
499
500ip1 link del veth1
501ip1 link del veth3
502ip1 link del wg0
503ip2 link del wg0
504
505# We test that Netlink/IPC is working properly by doing things that usually cause split responses
506ip0 link add dev wg0 type wireguard
507config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
508for a in {1..255}; do
509	for b in {0..255}; do
510		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
511	done
512done
513n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
514i=0
515for ip in $(n0 wg show wg0 allowed-ips); do
516	((++i))
517done
518((i == 255*256*2+1))
519ip0 link del wg0
520ip0 link add dev wg0 type wireguard
521config=( "[Interface]" "PrivateKey=$(wg genkey)" )
522for a in {1..40}; do
523	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
524	for b in {1..52}; do
525		config+=( "AllowedIPs=$a.$b.0.0/16" )
526	done
527done
528n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
529i=0
530while read -r line; do
531	j=0
532	for ip in $line; do
533		((++j))
534	done
535	((j == 53))
536	((++i))
537done < <(n0 wg show wg0 allowed-ips)
538((i == 40))
539ip0 link del wg0
540ip0 link add wg0 type wireguard
541config=( )
542for i in {1..29}; do
543	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
544done
545config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
546n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
547n0 wg showconf wg0 > /dev/null
548ip0 link del wg0
549
550allowedips=( )
551for i in {1..197}; do
552        allowedips+=( abcd::$i )
553done
554saved_ifs="$IFS"
555IFS=,
556allowedips="${allowedips[*]}"
557IFS="$saved_ifs"
558ip0 link add wg0 type wireguard
559n0 wg set wg0 peer "$pub1"
560n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
561{
562	read -r pub allowedips
563	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
564	read -r pub allowedips
565	[[ $pub == "$pub2" ]]
566	i=0
567	for _ in $allowedips; do
568		((++i))
569	done
570	((i == 197))
571} < <(n0 wg show wg0 allowed-ips)
572ip0 link del wg0
573
574! n0 wg show doesnotexist || false
575
576ip0 link add wg0 type wireguard
577n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
578[[ $(n0 wg show wg0 private-key) == "$key1" ]]
579[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
580n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
581[[ $(n0 wg show wg0 private-key) == "(none)" ]]
582[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
583n0 wg set wg0 peer "$pub2"
584n0 wg set wg0 private-key <(echo "$key2")
585[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
586[[ -z $(n0 wg show wg0 peers) ]]
587n0 wg set wg0 peer "$pub2"
588[[ -z $(n0 wg show wg0 peers) ]]
589n0 wg set wg0 private-key <(echo "$key1")
590n0 wg set wg0 peer "$pub2"
591[[ $(n0 wg show wg0 peers) == "$pub2" ]]
592n0 wg set wg0 private-key <(echo "/${key1:1}")
593[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
594n0 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
595n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
596n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
597n0 wg set wg0 peer "$pub2" allowed-ips ::/0
598n0 wg set wg0 peer "$pub2" remove
599for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
600	n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
601done
602[[ -n $(n0 wg show wg0 peers) ]]
603exec 4< <(n0 ncat -l -u -p 1111)
604ncat_pid=$!
605waitncatudp $netns0 $ncat_pid
606ip0 link set wg0 up
607! read -r -n 1 -t 2 <&4 || false
608kill $ncat_pid
609ip0 link del wg0
610
611# Ensure there aren't circular reference loops
612ip1 link add wg1 type wireguard
613ip2 link add wg2 type wireguard
614ip1 link set wg1 netns $netns2
615ip2 link set wg2 netns $netns1
616pp ip netns delete $netns1
617pp ip netns delete $netns2
618pp ip netns add $netns1
619pp ip netns add $netns2
620
621sleep 2 # Wait for cleanup and grace periods
622declare -A objects
623while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
624	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
625	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
626done < /dev/kmsg
627alldeleted=1
628for object in "${!objects[@]}"; do
629	if [[ ${objects["$object"]} != *createddestroyed ]]; then
630		echo "Error: $object: merely ${objects["$object"]}" >&3
631		alldeleted=0
632	fi
633done
634[[ $alldeleted -eq 1 ]]
635pretty "" "Objects that were created were also destroyed."
636