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:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 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
146[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
147big_mtu=$(( 34816 - 1500 + $orig_mtu ))
148
149# Test using IPv4 as outer transport
150n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
151n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
152# Before calling tests, we first make sure that the stats counters and timestamper are working
153n2 ping -c 10 -f -W 1 192.168.241.1
154{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
155(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
156{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
157(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
158read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
159(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
160read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
161(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
162read _ timestamp < <(n1 wg show wg0 latest-handshakes)
163(( timestamp != 0 ))
164
165tests
166ip1 link set wg0 mtu $big_mtu
167ip2 link set wg0 mtu $big_mtu
168tests
169
170ip1 link set wg0 mtu $orig_mtu
171ip2 link set wg0 mtu $orig_mtu
172
173# Test using IPv6 as outer transport
174n1 wg set wg0 peer "$pub2" endpoint [::1]:2
175n2 wg set wg0 peer "$pub1" endpoint [::1]:1
176tests
177ip1 link set wg0 mtu $big_mtu
178ip2 link set wg0 mtu $big_mtu
179tests
180
181# Test that route MTUs work with the padding
182ip1 link set wg0 mtu 1300
183ip2 link set wg0 mtu 1300
184n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
185n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
186n0 iptables -A INPUT -m length --length 1360 -j DROP
187n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
188n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
189n2 ping -c 1 -W 1 -s 1269 192.168.241.1
190n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
191n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
192n0 iptables -F INPUT
193
194ip1 link set wg0 mtu $orig_mtu
195ip2 link set wg0 mtu $orig_mtu
196
197# Test using IPv4 that roaming works
198ip0 -4 addr del 127.0.0.1/8 dev lo
199ip0 -4 addr add 127.212.121.99/8 dev lo
200n1 wg set wg0 listen-port 9999
201n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
202n1 ping6 -W 1 -c 1 fd00::2
203[[ $(n2 wg show wg0 endpoints) == "$pub1	127.212.121.99:9999" ]]
204
205# Test using IPv6 that roaming works
206n1 wg set wg0 listen-port 9998
207n1 wg set wg0 peer "$pub2" endpoint [::1]:2
208n1 ping -W 1 -c 1 192.168.241.2
209[[ $(n2 wg show wg0 endpoints) == "$pub1	[::1]:9998" ]]
210
211# Test that crypto-RP filter works
212n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
213exec 4< <(n1 ncat -l -u -p 1111)
214ncat_pid=$!
215waitncatudp $netns1 $ncat_pid
216n2 ncat -u 192.168.241.1 1111 <<<"X"
217read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
218kill $ncat_pid
219more_specific_key="$(pp wg genkey | pp wg pubkey)"
220n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
221n2 wg set wg0 listen-port 9997
222exec 4< <(n1 ncat -l -u -p 1111)
223ncat_pid=$!
224waitncatudp $netns1 $ncat_pid
225n2 ncat -u 192.168.241.1 1111 <<<"X"
226! read -r -N 1 -t 1 out <&4 || false
227kill $ncat_pid
228n1 wg set wg0 peer "$more_specific_key" remove
229[[ $(n1 wg show wg0 endpoints) == "$pub2	[::1]:9997" ]]
230
231# Test that we can change private keys keys and immediately handshake
232n1 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
233n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
234n1 ping -W 1 -c 1 192.168.241.2
235n1 wg set wg0 private-key <(echo "$key3")
236n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
237n1 ping -W 1 -c 1 192.168.241.2
238n2 wg set wg0 peer "$pub3" remove
239
240# Test that we can route wg through wg
241ip1 addr flush dev wg0
242ip2 addr flush dev wg0
243ip1 addr add fd00::5:1/112 dev wg0
244ip2 addr add fd00::5:2/112 dev wg0
245n1 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
246n2 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
247ip1 link add wg1 type wireguard
248ip2 link add wg1 type wireguard
249ip1 addr add 192.168.241.1/24 dev wg1
250ip1 addr add fd00::1/112 dev wg1
251ip2 addr add 192.168.241.2/24 dev wg1
252ip2 addr add fd00::2/112 dev wg1
253ip1 link set mtu 1340 up dev wg1
254ip2 link set mtu 1340 up dev wg1
255n1 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
256n2 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
257tests
258# Try to set up a routing loop between the two namespaces
259ip1 link set netns $netns0 dev wg1
260ip0 addr add 192.168.241.1/24 dev wg1
261ip0 link set up dev wg1
262n0 ping -W 1 -c 1 192.168.241.2
263n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
264ip2 link del wg0
265ip2 link del wg1
266! n0 ping -W 1 -c 10 -f 192.168.241.2 || false # Should not crash kernel
267
268ip0 link del wg1
269ip1 link del wg0
270
271# Test using NAT. We now change the topology to this:
272# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
273# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
274# │                                        │    │                                                │     │                                        │
275# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
276# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
277# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
278# │  │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│ │
279# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
280# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
281# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
282
283ip1 link add dev wg0 type wireguard
284ip2 link add dev wg0 type wireguard
285configure_peers
286
287ip0 link add vethrc type veth peer name vethc
288ip0 link add vethrs type veth peer name veths
289ip0 link set vethc netns $netns1
290ip0 link set veths netns $netns2
291ip0 link set vethrc up
292ip0 link set vethrs up
293ip0 addr add 192.168.1.1/24 dev vethrc
294ip0 addr add 10.0.0.1/24 dev vethrs
295ip1 addr add 192.168.1.100/24 dev vethc
296ip1 link set vethc up
297ip1 route add default via 192.168.1.1
298ip2 addr add 10.0.0.100/24 dev veths
299ip2 link set veths up
300waitiface $netns0 vethrc
301waitiface $netns0 vethrs
302waitiface $netns1 vethc
303waitiface $netns2 veths
304
305n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
306n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
307n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
308n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
309
310n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
311n1 ping -W 1 -c 1 192.168.241.2
312n2 ping -W 1 -c 1 192.168.241.1
313[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
314# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
315pp sleep 3
316n2 ping -W 1 -c 1 192.168.241.1
317n1 wg set wg0 peer "$pub2" persistent-keepalive 0
318
319# Test that sk_bound_dev_if works
320n1 ping -I wg0 -c 1 -W 1 192.168.241.2
321# What about when the mark changes and the packet must be rerouted?
322n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
323n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
324n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
325n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
326
327# Test that onion routing works, even when it loops
328n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
329ip1 addr add 192.168.242.1/24 dev wg0
330ip2 link add wg1 type wireguard
331ip2 addr add 192.168.242.2/24 dev wg1
332n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
333ip2 link set wg1 up
334n1 ping -W 1 -c 1 192.168.242.2
335ip2 link del wg1
336n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
337! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
338n1 wg set wg0 peer "$pub3" remove
339ip1 addr del 192.168.242.1/24 dev wg0
340
341# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
342ip1 -6 addr add fc00::9/96 dev vethc
343ip1 -6 route add default via fc00::1
344ip2 -4 addr add 192.168.99.7/32 dev wg0
345ip2 -6 addr add abab::1111/128 dev wg0
346n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
347ip1 -6 route add default dev wg0 table 51820
348ip1 -6 rule add not fwmark 51820 table 51820
349ip1 -6 rule add table main suppress_prefixlength 0
350ip1 -4 route add default dev wg0 table 51820
351ip1 -4 rule add not fwmark 51820 table 51820
352ip1 -4 rule add table main suppress_prefixlength 0
353# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
354n1 ping -W 1 -c 100 -f 192.168.99.7
355n1 ping -W 1 -c 100 -f abab::1111
356
357# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
358n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
359n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
360n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
361ip0 -4 route add 192.168.241.1 via 10.0.0.100
362n2 wg set wg0 peer "$pub1" remove
363[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
364
365n0 iptables -t nat -F
366n0 iptables -t filter -F
367n2 iptables -t nat -F
368ip0 link del vethrc
369ip0 link del vethrs
370ip1 link del wg0
371ip2 link del wg0
372
373# Test that saddr routing is sticky but not too sticky, changing to this topology:
374# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
375# │             $ns1 namespace             │    │             $ns2 namespace             │
376# │                                        │    │                                        │
377# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
378# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
379# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
380# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
381# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
382# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
383# └────────────────────────────────────────┘    └────────────────────────────────────────┘
384
385ip1 link add dev wg0 type wireguard
386ip2 link add dev wg0 type wireguard
387configure_peers
388ip1 link add veth1 type veth peer name veth2
389ip1 link set veth2 netns $netns2
390n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
391n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
392n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
393n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
394n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
395
396# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
397ip1 addr add 10.0.0.1/24 dev veth1
398ip1 addr add fd00:aa::1/96 dev veth1
399ip2 addr add 10.0.0.2/24 dev veth2
400ip2 addr add fd00:aa::2/96 dev veth2
401ip1 link set veth1 up
402ip2 link set veth2 up
403waitiface $netns1 veth1
404waitiface $netns2 veth2
405n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
406n1 ping -W 1 -c 1 192.168.241.2
407ip1 addr add 10.0.0.10/24 dev veth1
408ip1 addr del 10.0.0.1/24 dev veth1
409n1 ping -W 1 -c 1 192.168.241.2
410n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
411n1 ping -W 1 -c 1 192.168.241.2
412ip1 addr add fd00:aa::10/96 dev veth1
413ip1 addr del fd00:aa::1/96 dev veth1
414n1 ping -W 1 -c 1 192.168.241.2
415
416# Now we show that we can successfully do reply to sender routing
417ip1 link set veth1 down
418ip2 link set veth2 down
419ip1 addr flush dev veth1
420ip2 addr flush dev veth2
421ip1 addr add 10.0.0.1/24 dev veth1
422ip1 addr add 10.0.0.2/24 dev veth1
423ip1 addr add fd00:aa::1/96 dev veth1
424ip1 addr add fd00:aa::2/96 dev veth1
425ip2 addr add 10.0.0.3/24 dev veth2
426ip2 addr add fd00:aa::3/96 dev veth2
427ip1 link set veth1 up
428ip2 link set veth2 up
429waitiface $netns1 veth1
430waitiface $netns2 veth2
431n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
432n2 ping -W 1 -c 1 192.168.241.1
433[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
434n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
435n2 ping -W 1 -c 1 192.168.241.1
436[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
437n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
438n2 ping -W 1 -c 1 192.168.241.1
439[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
440n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
441n2 ping -W 1 -c 1 192.168.241.1
442[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
443
444# What happens if the inbound destination address belongs to a different interface as the default route?
445ip1 link add dummy0 type dummy
446ip1 addr add 10.50.0.1/24 dev dummy0
447ip1 link set dummy0 up
448ip2 route add 10.50.0.0/24 dev veth2
449n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
450n2 ping -W 1 -c 1 192.168.241.1
451[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
452
453ip1 link del dummy0
454ip1 addr flush dev veth1
455ip2 addr flush dev veth2
456ip1 route flush dev veth1
457ip2 route flush dev veth2
458
459# Now we see what happens if another interface route takes precedence over an ongoing one
460ip1 link add veth3 type veth peer name veth4
461ip1 link set veth4 netns $netns2
462ip1 addr add 10.0.0.1/24 dev veth1
463ip2 addr add 10.0.0.2/24 dev veth2
464ip1 addr add 10.0.0.3/24 dev veth3
465ip1 link set veth1 up
466ip2 link set veth2 up
467ip1 link set veth3 up
468ip2 link set veth4 up
469waitiface $netns1 veth1
470waitiface $netns2 veth2
471waitiface $netns1 veth3
472waitiface $netns2 veth4
473ip1 route flush dev veth1
474ip1 route flush dev veth3
475ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
476n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
477n1 ping -W 1 -c 1 192.168.241.2
478[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
479ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
480n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
481n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
482n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
483n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
484n1 ping -W 1 -c 1 192.168.241.2
485[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
486
487ip1 link del veth1
488ip1 link del veth3
489ip1 link del wg0
490ip2 link del wg0
491
492# We test that Netlink/IPC is working properly by doing things that usually cause split responses
493ip0 link add dev wg0 type wireguard
494config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
495for a in {1..255}; do
496	for b in {0..255}; do
497		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
498	done
499done
500n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
501i=0
502for ip in $(n0 wg show wg0 allowed-ips); do
503	((++i))
504done
505((i == 255*256*2+1))
506ip0 link del wg0
507ip0 link add dev wg0 type wireguard
508config=( "[Interface]" "PrivateKey=$(wg genkey)" )
509for a in {1..40}; do
510	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
511	for b in {1..52}; do
512		config+=( "AllowedIPs=$a.$b.0.0/16" )
513	done
514done
515n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
516i=0
517while read -r line; do
518	j=0
519	for ip in $line; do
520		((++j))
521	done
522	((j == 53))
523	((++i))
524done < <(n0 wg show wg0 allowed-ips)
525((i == 40))
526ip0 link del wg0
527ip0 link add wg0 type wireguard
528config=( )
529for i in {1..29}; do
530	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
531done
532config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
533n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
534n0 wg showconf wg0 > /dev/null
535ip0 link del wg0
536
537allowedips=( )
538for i in {1..197}; do
539        allowedips+=( abcd::$i )
540done
541saved_ifs="$IFS"
542IFS=,
543allowedips="${allowedips[*]}"
544IFS="$saved_ifs"
545ip0 link add wg0 type wireguard
546n0 wg set wg0 peer "$pub1"
547n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
548{
549	read -r pub allowedips
550	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
551	read -r pub allowedips
552	[[ $pub == "$pub2" ]]
553	i=0
554	for _ in $allowedips; do
555		((++i))
556	done
557	((i == 197))
558} < <(n0 wg show wg0 allowed-ips)
559ip0 link del wg0
560
561! n0 wg show doesnotexist || false
562
563ip0 link add wg0 type wireguard
564n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
565[[ $(n0 wg show wg0 private-key) == "$key1" ]]
566[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
567n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
568[[ $(n0 wg show wg0 private-key) == "(none)" ]]
569[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
570n0 wg set wg0 peer "$pub2"
571n0 wg set wg0 private-key <(echo "$key2")
572[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
573[[ -z $(n0 wg show wg0 peers) ]]
574n0 wg set wg0 peer "$pub2"
575[[ -z $(n0 wg show wg0 peers) ]]
576n0 wg set wg0 private-key <(echo "$key1")
577n0 wg set wg0 peer "$pub2"
578[[ $(n0 wg show wg0 peers) == "$pub2" ]]
579n0 wg set wg0 private-key <(echo "/${key1:1}")
580[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
581n0 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
582n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
583n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
584n0 wg set wg0 peer "$pub2" allowed-ips ::/0
585n0 wg set wg0 peer "$pub2" remove
586for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
587	n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
588done
589[[ -n $(n0 wg show wg0 peers) ]]
590exec 4< <(n0 ncat -l -u -p 1111)
591ncat_pid=$!
592waitncatudp $netns0 $ncat_pid
593ip0 link set wg0 up
594! read -r -n 1 -t 2 <&4 || false
595kill $ncat_pid
596ip0 link del wg0
597
598# Ensure there aren't circular reference loops
599ip1 link add wg1 type wireguard
600ip2 link add wg2 type wireguard
601ip1 link set wg1 netns $netns2
602ip2 link set wg2 netns $netns1
603pp ip netns delete $netns1
604pp ip netns delete $netns2
605pp ip netns add $netns1
606pp ip netns add $netns2
607
608sleep 2 # Wait for cleanup and grace periods
609declare -A objects
610while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
611	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
612	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
613done < /dev/kmsg
614alldeleted=1
615for object in "${!objects[@]}"; do
616	if [[ ${objects["$object"]} != *createddestroyed ]]; then
617		echo "Error: $object: merely ${objects["$object"]}" >&3
618		alldeleted=0
619	fi
620done
621[[ $alldeleted -eq 1 ]]
622pretty "" "Objects that were created were also destroyed."
623