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 WG_HIDE_KEYS=never
28netns0="wg-test-$$-0"
29netns1="wg-test-$$-1"
30netns2="wg-test-$$-2"
31pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
32pp() { pretty "" "$*"; "$@"; }
33maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
34n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
35n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
36n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
37ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
38ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
39ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
40sleep() { read -t "$1" -N 1 || true; }
41waitiperf() { pretty "${1//*-}" "wait for iperf:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 5201') != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; }
42waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
43waitiface() { 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;"; }
44
45cleanup() {
46	set +e
47	exec 2>/dev/null
48	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
49	ip0 link del dev wg0
50	ip1 link del dev wg0
51	ip2 link del dev wg0
52	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
53	[[ -n $to_kill ]] && kill $to_kill
54	pp ip netns del $netns1
55	pp ip netns del $netns2
56	pp ip netns del $netns0
57	exit
58}
59
60orig_message_cost="$(< /proc/sys/net/core/message_cost)"
61trap cleanup EXIT
62printf 0 > /proc/sys/net/core/message_cost
63
64ip netns del $netns0 2>/dev/null || true
65ip netns del $netns1 2>/dev/null || true
66ip netns del $netns2 2>/dev/null || true
67pp ip netns add $netns0
68pp ip netns add $netns1
69pp ip netns add $netns2
70ip0 link set up dev lo
71
72ip0 link add dev wg0 type wireguard
73ip0 link set wg0 netns $netns1
74ip0 link add dev wg0 type wireguard
75ip0 link set wg0 netns $netns2
76key1="$(pp wg genkey)"
77key2="$(pp wg genkey)"
78key3="$(pp wg genkey)"
79pub1="$(pp wg pubkey <<<"$key1")"
80pub2="$(pp wg pubkey <<<"$key2")"
81pub3="$(pp wg pubkey <<<"$key3")"
82psk="$(pp wg genpsk)"
83[[ -n $key1 && -n $key2 && -n $psk ]]
84
85configure_peers() {
86	ip1 addr add 192.168.241.1/24 dev wg0
87	ip1 addr add fd00::1/24 dev wg0
88
89	ip2 addr add 192.168.241.2/24 dev wg0
90	ip2 addr add fd00::2/24 dev wg0
91
92	n1 wg set wg0 \
93		private-key <(echo "$key1") \
94		listen-port 1 \
95		peer "$pub2" \
96			preshared-key <(echo "$psk") \
97			allowed-ips 192.168.241.2/32,fd00::2/128
98	n2 wg set wg0 \
99		private-key <(echo "$key2") \
100		listen-port 2 \
101		peer "$pub1" \
102			preshared-key <(echo "$psk") \
103			allowed-ips 192.168.241.1/32,fd00::1/128
104
105	ip1 link set up dev wg0
106	ip2 link set up dev wg0
107}
108configure_peers
109
110tests() {
111	# Ping over IPv4
112	n2 ping -c 10 -f -W 1 192.168.241.1
113	n1 ping -c 10 -f -W 1 192.168.241.2
114
115	# Ping over IPv6
116	n2 ping6 -c 10 -f -W 1 fd00::1
117	n1 ping6 -c 10 -f -W 1 fd00::2
118
119	# TCP over IPv4
120	n2 iperf3 -s -1 -B 192.168.241.2 &
121	waitiperf $netns2 $!
122	n1 iperf3 -Z -t 3 -c 192.168.241.2
123
124	# TCP over IPv6
125	n1 iperf3 -s -1 -B fd00::1 &
126	waitiperf $netns1 $!
127	n2 iperf3 -Z -t 3 -c fd00::1
128
129	# UDP over IPv4
130	n1 iperf3 -s -1 -B 192.168.241.1 &
131	waitiperf $netns1 $!
132	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
133
134	# UDP over IPv6
135	n2 iperf3 -s -1 -B fd00::2 &
136	waitiperf $netns2 $!
137	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
138}
139
140[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
141big_mtu=$(( 34816 - 1500 + $orig_mtu ))
142
143# Test using IPv4 as outer transport
144n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
145n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
146# Before calling tests, we first make sure that the stats counters and timestamper are working
147n2 ping -c 10 -f -W 1 192.168.241.1
148{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
149(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
150{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
151(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
152read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
153(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
154read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
155(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
156read _ timestamp < <(n1 wg show wg0 latest-handshakes)
157(( timestamp != 0 ))
158
159tests
160ip1 link set wg0 mtu $big_mtu
161ip2 link set wg0 mtu $big_mtu
162tests
163
164ip1 link set wg0 mtu $orig_mtu
165ip2 link set wg0 mtu $orig_mtu
166
167# Test using IPv6 as outer transport
168n1 wg set wg0 peer "$pub2" endpoint [::1]:2
169n2 wg set wg0 peer "$pub1" endpoint [::1]:1
170tests
171ip1 link set wg0 mtu $big_mtu
172ip2 link set wg0 mtu $big_mtu
173tests
174
175# Test that route MTUs work with the padding
176ip1 link set wg0 mtu 1300
177ip2 link set wg0 mtu 1300
178n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
179n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
180n0 iptables -A INPUT -m length --length 1360 -j DROP
181n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
182n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
183n2 ping -c 1 -W 1 -s 1269 192.168.241.1
184n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
185n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
186n0 iptables -F INPUT
187
188ip1 link set wg0 mtu $orig_mtu
189ip2 link set wg0 mtu $orig_mtu
190
191# Test using IPv4 that roaming works
192ip0 -4 addr del 127.0.0.1/8 dev lo
193ip0 -4 addr add 127.212.121.99/8 dev lo
194n1 wg set wg0 listen-port 9999
195n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
196n1 ping6 -W 1 -c 1 fd00::2
197[[ $(n2 wg show wg0 endpoints) == "$pub1	127.212.121.99:9999" ]]
198
199# Test using IPv6 that roaming works
200n1 wg set wg0 listen-port 9998
201n1 wg set wg0 peer "$pub2" endpoint [::1]:2
202n1 ping -W 1 -c 1 192.168.241.2
203[[ $(n2 wg show wg0 endpoints) == "$pub1	[::1]:9998" ]]
204
205# Test that crypto-RP filter works
206n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
207exec 4< <(n1 ncat -l -u -p 1111)
208ncat_pid=$!
209waitncatudp $netns1 $ncat_pid
210n2 ncat -u 192.168.241.1 1111 <<<"X"
211read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
212kill $ncat_pid
213more_specific_key="$(pp wg genkey | pp wg pubkey)"
214n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
215n2 wg set wg0 listen-port 9997
216exec 4< <(n1 ncat -l -u -p 1111)
217ncat_pid=$!
218waitncatudp $netns1 $ncat_pid
219n2 ncat -u 192.168.241.1 1111 <<<"X"
220! read -r -N 1 -t 1 out <&4 || false
221kill $ncat_pid
222n1 wg set wg0 peer "$more_specific_key" remove
223[[ $(n1 wg show wg0 endpoints) == "$pub2	[::1]:9997" ]]
224
225# Test that we can change private keys keys and immediately handshake
226n1 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
227n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
228n1 ping -W 1 -c 1 192.168.241.2
229n1 wg set wg0 private-key <(echo "$key3")
230n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
231n1 ping -W 1 -c 1 192.168.241.2
232
233ip1 link del wg0
234ip2 link del wg0
235
236# Test using NAT. We now change the topology to this:
237# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
238# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
239# │                                        │    │                                                │     │                                        │
240# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
241# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
242# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
243# │  │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│ │
244# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
245# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
246# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
247
248ip1 link add dev wg0 type wireguard
249ip2 link add dev wg0 type wireguard
250configure_peers
251
252ip0 link add vethrc type veth peer name vethc
253ip0 link add vethrs type veth peer name veths
254ip0 link set vethc netns $netns1
255ip0 link set veths netns $netns2
256ip0 link set vethrc up
257ip0 link set vethrs up
258ip0 addr add 192.168.1.1/24 dev vethrc
259ip0 addr add 10.0.0.1/24 dev vethrs
260ip1 addr add 192.168.1.100/24 dev vethc
261ip1 link set vethc up
262ip1 route add default via 192.168.1.1
263ip2 addr add 10.0.0.100/24 dev veths
264ip2 link set veths up
265waitiface $netns0 vethrc
266waitiface $netns0 vethrs
267waitiface $netns1 vethc
268waitiface $netns2 veths
269
270n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
271n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
272n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
273n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
274
275n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
276n1 ping -W 1 -c 1 192.168.241.2
277n2 ping -W 1 -c 1 192.168.241.1
278[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
279# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
280pp sleep 3
281n2 ping -W 1 -c 1 192.168.241.1
282n1 wg set wg0 peer "$pub2" persistent-keepalive 0
283
284# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
285ip1 -6 addr add fc00::9/96 dev vethc
286ip1 -6 route add default via fc00::1
287ip2 -4 addr add 192.168.99.7/32 dev wg0
288ip2 -6 addr add abab::1111/128 dev wg0
289n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
290ip1 -6 route add default dev wg0 table 51820
291ip1 -6 rule add not fwmark 51820 table 51820
292ip1 -6 rule add table main suppress_prefixlength 0
293ip1 -4 route add default dev wg0 table 51820
294ip1 -4 rule add not fwmark 51820 table 51820
295ip1 -4 rule add table main suppress_prefixlength 0
296# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
297n1 ping -W 1 -c 100 -f 192.168.99.7
298n1 ping -W 1 -c 100 -f abab::1111
299
300n0 iptables -t nat -F
301ip0 link del vethrc
302ip0 link del vethrs
303ip1 link del wg0
304ip2 link del wg0
305
306# Test that saddr routing is sticky but not too sticky, changing to this topology:
307# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
308# │             $ns1 namespace             │    │             $ns2 namespace             │
309# │                                        │    │                                        │
310# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
311# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
312# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
313# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
314# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
315# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
316# └────────────────────────────────────────┘    └────────────────────────────────────────┘
317
318ip1 link add dev wg0 type wireguard
319ip2 link add dev wg0 type wireguard
320configure_peers
321ip1 link add veth1 type veth peer name veth2
322ip1 link set veth2 netns $netns2
323n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
324n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
325n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
326n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
327n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
328
329# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
330ip1 addr add 10.0.0.1/24 dev veth1
331ip1 addr add fd00:aa::1/96 dev veth1
332ip2 addr add 10.0.0.2/24 dev veth2
333ip2 addr add fd00:aa::2/96 dev veth2
334ip1 link set veth1 up
335ip2 link set veth2 up
336waitiface $netns1 veth1
337waitiface $netns2 veth2
338n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
339n1 ping -W 1 -c 1 192.168.241.2
340ip1 addr add 10.0.0.10/24 dev veth1
341ip1 addr del 10.0.0.1/24 dev veth1
342n1 ping -W 1 -c 1 192.168.241.2
343n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
344n1 ping -W 1 -c 1 192.168.241.2
345ip1 addr add fd00:aa::10/96 dev veth1
346ip1 addr del fd00:aa::1/96 dev veth1
347n1 ping -W 1 -c 1 192.168.241.2
348
349# Now we show that we can successfully do reply to sender routing
350ip1 link set veth1 down
351ip2 link set veth2 down
352ip1 addr flush dev veth1
353ip2 addr flush dev veth2
354ip1 addr add 10.0.0.1/24 dev veth1
355ip1 addr add 10.0.0.2/24 dev veth1
356ip1 addr add fd00:aa::1/96 dev veth1
357ip1 addr add fd00:aa::2/96 dev veth1
358ip2 addr add 10.0.0.3/24 dev veth2
359ip2 addr add fd00:aa::3/96 dev veth2
360ip1 link set veth1 up
361ip2 link set veth2 up
362waitiface $netns1 veth1
363waitiface $netns2 veth2
364n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
365n2 ping -W 1 -c 1 192.168.241.1
366[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
367n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
368n2 ping -W 1 -c 1 192.168.241.1
369[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
370n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
371n2 ping -W 1 -c 1 192.168.241.1
372[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
373n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
374n2 ping -W 1 -c 1 192.168.241.1
375[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
376
377# What happens if the inbound destination address belongs to a different interface as the default route?
378ip1 link add dummy0 type dummy
379ip1 addr add 10.50.0.1/24 dev dummy0
380ip1 link set dummy0 up
381ip2 route add 10.50.0.0/24 dev veth2
382n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
383n2 ping -W 1 -c 1 192.168.241.1
384[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
385
386ip1 link del dummy0
387ip1 addr flush dev veth1
388ip2 addr flush dev veth2
389ip1 route flush dev veth1
390ip2 route flush dev veth2
391
392# Now we see what happens if another interface route takes precedence over an ongoing one
393ip1 link add veth3 type veth peer name veth4
394ip1 link set veth4 netns $netns2
395ip1 addr add 10.0.0.1/24 dev veth1
396ip2 addr add 10.0.0.2/24 dev veth2
397ip1 addr add 10.0.0.3/24 dev veth3
398ip1 link set veth1 up
399ip2 link set veth2 up
400ip1 link set veth3 up
401ip2 link set veth4 up
402waitiface $netns1 veth1
403waitiface $netns2 veth2
404waitiface $netns1 veth3
405waitiface $netns2 veth4
406ip1 route flush dev veth1
407ip1 route flush dev veth3
408ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
409n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
410n1 ping -W 1 -c 1 192.168.241.2
411[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
412ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
413n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
414n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
415n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
416n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
417n1 ping -W 1 -c 1 192.168.241.2
418[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
419
420ip1 link del veth1
421ip1 link del veth3
422ip1 link del wg0
423ip2 link del wg0
424
425# We test that Netlink/IPC is working properly by doing things that usually cause split responses
426ip0 link add dev wg0 type wireguard
427config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
428for a in {1..255}; do
429	for b in {0..255}; do
430		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
431	done
432done
433n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
434i=0
435for ip in $(n0 wg show wg0 allowed-ips); do
436	((++i))
437done
438((i == 255*256*2+1))
439ip0 link del wg0
440ip0 link add dev wg0 type wireguard
441config=( "[Interface]" "PrivateKey=$(wg genkey)" )
442for a in {1..40}; do
443	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
444	for b in {1..52}; do
445		config+=( "AllowedIPs=$a.$b.0.0/16" )
446	done
447done
448n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
449i=0
450while read -r line; do
451	j=0
452	for ip in $line; do
453		((++j))
454	done
455	((j == 53))
456	((++i))
457done < <(n0 wg show wg0 allowed-ips)
458((i == 40))
459ip0 link del wg0
460ip0 link add wg0 type wireguard
461config=( )
462for i in {1..29}; do
463	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
464done
465config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
466n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
467n0 wg showconf wg0 > /dev/null
468ip0 link del wg0
469
470allowedips=( )
471for i in {1..197}; do
472        allowedips+=( abcd::$i )
473done
474saved_ifs="$IFS"
475IFS=,
476allowedips="${allowedips[*]}"
477IFS="$saved_ifs"
478ip0 link add wg0 type wireguard
479n0 wg set wg0 peer "$pub1"
480n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
481{
482	read -r pub allowedips
483	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
484	read -r pub allowedips
485	[[ $pub == "$pub2" ]]
486	i=0
487	for _ in $allowedips; do
488		((++i))
489	done
490	((i == 197))
491} < <(n0 wg show wg0 allowed-ips)
492ip0 link del wg0
493
494! n0 wg show doesnotexist || false
495
496ip0 link add wg0 type wireguard
497n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
498[[ $(n0 wg show wg0 private-key) == "$key1" ]]
499[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
500n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
501[[ $(n0 wg show wg0 private-key) == "(none)" ]]
502[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
503n0 wg set wg0 peer "$pub2"
504n0 wg set wg0 private-key <(echo "$key2")
505[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
506[[ -z $(n0 wg show wg0 peers) ]]
507n0 wg set wg0 peer "$pub2"
508[[ -z $(n0 wg show wg0 peers) ]]
509n0 wg set wg0 private-key <(echo "$key1")
510n0 wg set wg0 peer "$pub2"
511[[ $(n0 wg show wg0 peers) == "$pub2" ]]
512n0 wg set wg0 private-key <(echo "/${key1:1}")
513[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
514n0 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
515n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
516n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
517n0 wg set wg0 peer "$pub2" allowed-ips ::/0
518n0 wg set wg0 peer "$pub2" remove
519low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
520n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
521[[ -z $(n0 wg show wg0 peers) ]]
522n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
523[[ -z $(n0 wg show wg0 peers) ]]
524ip0 link del wg0
525
526declare -A objects
527while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
528	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue
529	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
530done < /dev/kmsg
531alldeleted=1
532for object in "${!objects[@]}"; do
533	if [[ ${objects["$object"]} != *createddestroyed ]]; then
534		echo "Error: $object: merely ${objects["$object"]}" >&3
535		alldeleted=0
536	fi
537done
538[[ $alldeleted -eq 1 ]]
539pretty "" "Objects that were created were also destroyed."
540