2 # SPDX-License-Identifier: GPL-2.0
6 # This script tests the below topology:
8 # ┌─────────────────────┐ ┌──────────────────────────────────┐ ┌─────────────────────┐
9 # │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │
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 # └──────────────────────────────────┘
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.
29 export WG_HIDE_KEYS=never
30 NPROC=( /sys/devices/system/cpu/cpu+([0-9]) ); NPROC=${#NPROC[@]}
34 pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
35 pp() { pretty "" "$*"; "$@"; }
36 maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
37 n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
38 n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
39 n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
40 ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
41 ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
42 ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
43 sleep() { read -t "$1" -N 1 || true; }
44 waitiperf() { 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; }
45 waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
46 waitiface() { 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;"; }
51 printf "$orig_message_cost" > /proc/sys/net/core/message_cost
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
66 orig_message_cost="$(< /proc/sys/net/core/message_cost)"
68 printf 0 > /proc/sys/net/core/message_cost
70 ip netns del $netns0 2>/dev/null || true
71 ip netns del $netns1 2>/dev/null || true
72 ip netns del $netns2 2>/dev/null || true
73 pp ip netns add $netns0
74 pp ip netns add $netns1
75 pp ip netns add $netns2
76 ip0 link set up dev lo
78 ip0 link add dev wg0 type wireguard
79 ip0 link set wg0 netns $netns1
80 ip0 link add dev wg0 type wireguard
81 ip0 link set wg0 netns $netns2
82 key1="$(pp wg genkey)"
83 key2="$(pp wg genkey)"
84 key3="$(pp wg genkey)"
85 key4="$(pp wg genkey)"
86 pub1="$(pp wg pubkey <<<"$key1")"
87 pub2="$(pp wg pubkey <<<"$key2")"
88 pub3="$(pp wg pubkey <<<"$key3")"
89 pub4="$(pp wg pubkey <<<"$key4")"
91 [[ -n $key1 && -n $key2 && -n $psk ]]
94 ip1 addr add 192.168.241.1/24 dev wg0
95 ip1 addr add fd00::1/112 dev wg0
97 ip2 addr add 192.168.241.2/24 dev wg0
98 ip2 addr add fd00::2/112 dev wg0
101 private-key <(echo "$key1") \
104 preshared-key <(echo "$psk") \
105 allowed-ips 192.168.241.2/32,fd00::2/128
107 private-key <(echo "$key2") \
110 preshared-key <(echo "$psk") \
111 allowed-ips 192.168.241.1/32,fd00::1/128
113 ip1 link set up dev wg0
114 ip2 link set up dev wg0
120 n2 ping -c 10 -f -W 1 192.168.241.1
121 n1 ping -c 10 -f -W 1 192.168.241.2
124 n2 ping6 -c 10 -f -W 1 fd00::1
125 n1 ping6 -c 10 -f -W 1 fd00::2
128 n2 iperf3 -s -1 -B 192.168.241.2 &
130 n1 iperf3 -Z -t 3 -c 192.168.241.2
133 n1 iperf3 -s -1 -B fd00::1 &
135 n2 iperf3 -Z -t 3 -c fd00::1
138 n1 iperf3 -s -1 -B 192.168.241.1 &
140 n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
143 n2 iperf3 -s -1 -B fd00::2 &
145 n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
147 # TCP over IPv4, in parallel
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 ))
153 for ((i=0; i < NPROC; ++i)) do
154 n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
159 [[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
160 big_mtu=$(( 34816 - 1500 + $orig_mtu ))
162 # Test using IPv4 as outer transport
163 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
164 n2 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
166 n2 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) ))
171 read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
172 (( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
173 read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
174 (( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
175 read _ timestamp < <(n1 wg show wg0 latest-handshakes)
179 ip1 link set wg0 mtu $big_mtu
180 ip2 link set wg0 mtu $big_mtu
183 ip1 link set wg0 mtu $orig_mtu
184 ip2 link set wg0 mtu $orig_mtu
186 # Test using IPv6 as outer transport
187 n1 wg set wg0 peer "$pub2" endpoint [::1]:2
188 n2 wg set wg0 peer "$pub1" endpoint [::1]:1
190 ip1 link set wg0 mtu $big_mtu
191 ip2 link set wg0 mtu $big_mtu
194 # Test that route MTUs work with the padding
195 ip1 link set wg0 mtu 1300
196 ip2 link set wg0 mtu 1300
197 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
198 n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
199 n0 iptables -A INPUT -m length --length 1360 -j DROP
200 n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
201 n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
202 n2 ping -c 1 -W 1 -s 1269 192.168.241.1
203 n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
204 n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
207 ip1 link set wg0 mtu $orig_mtu
208 ip2 link set wg0 mtu $orig_mtu
210 # Test using IPv4 that roaming works
211 ip0 -4 addr del 127.0.0.1/8 dev lo
212 ip0 -4 addr add 127.212.121.99/8 dev lo
213 n1 wg set wg0 listen-port 9999
214 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
215 n1 ping6 -W 1 -c 1 fd00::2
216 [[ $(n2 wg show wg0 endpoints) == "$pub1 127.212.121.99:9999" ]]
218 # Test using IPv6 that roaming works
219 n1 wg set wg0 listen-port 9998
220 n1 wg set wg0 peer "$pub2" endpoint [::1]:2
221 n1 ping -W 1 -c 1 192.168.241.2
222 [[ $(n2 wg show wg0 endpoints) == "$pub1 [::1]:9998" ]]
224 # Test that crypto-RP filter works
225 n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
226 exec 4< <(n1 ncat -l -u -p 1111)
228 waitncatudp $netns1 $ncat_pid
229 n2 ncat -u 192.168.241.1 1111 <<<"X"
230 read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
232 more_specific_key="$(pp wg genkey | pp wg pubkey)"
233 n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
234 n2 wg set wg0 listen-port 9997
235 exec 4< <(n1 ncat -l -u -p 1111)
237 waitncatudp $netns1 $ncat_pid
238 n2 ncat -u 192.168.241.1 1111 <<<"X"
239 ! read -r -N 1 -t 1 out <&4 || false
241 n1 wg set wg0 peer "$more_specific_key" remove
242 [[ $(n1 wg show wg0 endpoints) == "$pub2 [::1]:9997" ]]
244 # Test that we can change private keys keys and immediately handshake
245 n1 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
246 n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
247 n1 ping -W 1 -c 1 192.168.241.2
248 n1 wg set wg0 private-key <(echo "$key3")
249 n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
250 n1 ping -W 1 -c 1 192.168.241.2
251 n2 wg set wg0 peer "$pub3" remove
253 # Test that we can route wg through wg
254 ip1 addr flush dev wg0
255 ip2 addr flush dev wg0
256 ip1 addr add fd00::5:1/112 dev wg0
257 ip2 addr add fd00::5:2/112 dev wg0
258 n1 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
259 n2 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
260 ip1 link add wg1 type wireguard
261 ip2 link add wg1 type wireguard
262 ip1 addr add 192.168.241.1/24 dev wg1
263 ip1 addr add fd00::1/112 dev wg1
264 ip2 addr add 192.168.241.2/24 dev wg1
265 ip2 addr add fd00::2/112 dev wg1
266 ip1 link set mtu 1340 up dev wg1
267 ip2 link set mtu 1340 up dev wg1
268 n1 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
269 n2 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
271 # Try to set up a routing loop between the two namespaces
272 ip1 link set netns $netns0 dev wg1
273 ip0 addr add 192.168.241.1/24 dev wg1
274 ip0 link set up dev wg1
275 n0 ping -W 1 -c 1 192.168.241.2
276 n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
279 read _ _ tx_bytes_before < <(n0 wg show wg1 transfer)
280 ! n0 ping -W 1 -c 10 -f 192.168.241.2 || false
282 read _ _ tx_bytes_after < <(n0 wg show wg1 transfer)
283 if ! (( tx_bytes_after - tx_bytes_before < 70000 )); then
284 errstart=$'\x1b[37m\x1b[41m\x1b[1m'
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}"
300 # Test using NAT. We now change the topology to this:
301 # ┌────────────────────────────────────────┐ ┌────────────────────────────────────────────────┐ ┌────────────────────────────────────────┐
302 # │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │
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 # └────────────────────────────────────────┘ └────────────────────────────────────────────────┘ └────────────────────────────────────────┘
312 ip1 link add dev wg0 type wireguard
313 ip2 link add dev wg0 type wireguard
316 ip0 link add vethrc type veth peer name vethc
317 ip0 link add vethrs type veth peer name veths
318 ip0 link set vethc netns $netns1
319 ip0 link set veths netns $netns2
320 ip0 link set vethrc up
321 ip0 link set vethrs up
322 ip0 addr add 192.168.1.1/24 dev vethrc
323 ip0 addr add 10.0.0.1/24 dev vethrs
324 ip1 addr add 192.168.1.100/24 dev vethc
325 ip1 link set vethc up
326 ip1 route add default via 192.168.1.1
327 ip2 addr add 10.0.0.100/24 dev veths
328 ip2 link set veths up
329 waitiface $netns0 vethrc
330 waitiface $netns0 vethrs
331 waitiface $netns1 vethc
332 waitiface $netns2 veths
334 n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
335 [[ -e /proc/sys/net/netfilter/nf_conntrack_udp_timeout ]] || modprobe nf_conntrack
336 n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
337 n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
338 n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
340 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
341 n1 ping -W 1 -c 1 192.168.241.2
342 n2 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`).
346 n2 ping -W 1 -c 1 192.168.241.1
347 n1 wg set wg0 peer "$pub2" persistent-keepalive 0
349 # Test that sk_bound_dev_if works
350 n1 ping -I wg0 -c 1 -W 1 192.168.241.2
351 # What about when the mark changes and the packet must be rerouted?
352 n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
353 n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
354 n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
355 n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
357 # Test that onion routing works, even when it loops
358 n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
359 ip1 addr add 192.168.242.1/24 dev wg0
360 ip2 link add wg1 type wireguard
361 ip2 addr add 192.168.242.2/24 dev wg1
362 n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
364 n1 ping -W 1 -c 1 192.168.242.2
366 n1 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
368 n1 wg set wg0 peer "$pub3" remove
369 ip1 addr del 192.168.242.1/24 dev wg0
371 # Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
372 ip1 -6 addr add fc00::9/96 dev vethc
373 ip1 -6 route add default via fc00::1
374 ip2 -4 addr add 192.168.99.7/32 dev wg0
375 ip2 -6 addr add abab::1111/128 dev wg0
376 n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
377 ip1 -6 route add default dev wg0 table 51820
378 ip1 -6 rule add not fwmark 51820 table 51820
379 ip1 -6 rule add table main suppress_prefixlength 0
380 ip1 -4 route add default dev wg0 table 51820
381 ip1 -4 rule add not fwmark 51820 table 51820
382 ip1 -4 rule add table main suppress_prefixlength 0
383 n1 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.
385 n1 ping -W 1 -c 100 -f 192.168.99.7
386 n1 ping -W 1 -c 100 -f abab::1111
388 # Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
389 n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
390 n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
391 n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
392 ip0 -4 route add 192.168.241.1 via 10.0.0.100
393 n2 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"* ]]
396 n0 iptables -t nat -F
397 n0 iptables -t filter -F
398 n2 iptables -t nat -F
404 # Test that saddr routing is sticky but not too sticky, changing to this topology:
405 # ┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐
406 # │ $ns1 namespace │ │ $ns2 namespace │
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 # └────────────────────────────────────────┘ └────────────────────────────────────────┘
416 ip1 link add dev wg0 type wireguard
417 ip2 link add dev wg0 type wireguard
419 ip1 link add veth1 type veth peer name veth2
420 ip1 link set veth2 netns $netns2
421 n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
422 n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
423 n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
424 n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
425 n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
427 # First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
428 ip1 addr add 10.0.0.1/24 dev veth1
429 ip1 addr add fd00:aa::1/96 dev veth1
430 ip2 addr add 10.0.0.2/24 dev veth2
431 ip2 addr add fd00:aa::2/96 dev veth2
432 ip1 link set veth1 up
433 ip2 link set veth2 up
434 waitiface $netns1 veth1
435 waitiface $netns2 veth2
436 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
437 n1 ping -W 1 -c 1 192.168.241.2
438 ip1 addr add 10.0.0.10/24 dev veth1
439 ip1 addr del 10.0.0.1/24 dev veth1
440 n1 ping -W 1 -c 1 192.168.241.2
441 n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
442 n1 ping -W 1 -c 1 192.168.241.2
443 ip1 addr add fd00:aa::10/96 dev veth1
444 ip1 addr del fd00:aa::1/96 dev veth1
445 n1 ping -W 1 -c 1 192.168.241.2
447 # Now we show that we can successfully do reply to sender routing
448 ip1 link set veth1 down
449 ip2 link set veth2 down
450 ip1 addr flush dev veth1
451 ip2 addr flush dev veth2
452 ip1 addr add 10.0.0.1/24 dev veth1
453 ip1 addr add 10.0.0.2/24 dev veth1
454 ip1 addr add fd00:aa::1/96 dev veth1
455 ip1 addr add fd00:aa::2/96 dev veth1
456 ip2 addr add 10.0.0.3/24 dev veth2
457 ip2 addr add fd00:aa::3/96 dev veth2
458 ip1 link set veth1 up
459 ip2 link set veth2 up
460 waitiface $netns1 veth1
461 waitiface $netns2 veth2
462 n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
463 n2 ping -W 1 -c 1 192.168.241.1
464 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]]
465 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
466 n2 ping -W 1 -c 1 192.168.241.1
467 [[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::1]:1" ]]
468 n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
469 n2 ping -W 1 -c 1 192.168.241.1
470 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.2:1" ]]
471 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
472 n2 ping -W 1 -c 1 192.168.241.1
473 [[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::2]:1" ]]
475 # What happens if the inbound destination address belongs to a different interface as the default route?
476 ip1 link add dummy0 type dummy
477 ip1 addr add 10.50.0.1/24 dev dummy0
478 ip1 link set dummy0 up
479 ip2 route add 10.50.0.0/24 dev veth2
480 n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
481 n2 ping -W 1 -c 1 192.168.241.1
482 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.50.0.1:1" ]]
485 ip1 addr flush dev veth1
486 ip2 addr flush dev veth2
487 ip1 route flush dev veth1
488 ip2 route flush dev veth2
490 # Now we see what happens if another interface route takes precedence over an ongoing one
491 ip1 link add veth3 type veth peer name veth4
492 ip1 link set veth4 netns $netns2
493 ip1 addr add 10.0.0.1/24 dev veth1
494 ip2 addr add 10.0.0.2/24 dev veth2
495 ip1 addr add 10.0.0.3/24 dev veth3
496 ip1 link set veth1 up
497 ip2 link set veth2 up
498 ip1 link set veth3 up
499 ip2 link set veth4 up
500 waitiface $netns1 veth1
501 waitiface $netns2 veth2
502 waitiface $netns1 veth3
503 waitiface $netns2 veth4
504 ip1 route flush dev veth1
505 ip1 route flush dev veth3
506 ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
507 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
508 n1 ping -W 1 -c 1 192.168.241.2
509 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]]
510 ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
511 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
512 n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
513 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
514 n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
515 n1 ping -W 1 -c 1 192.168.241.2
516 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.3:1" ]]
518 ip1 link del dev veth3
522 # Make sure persistent keep alives are sent when an adapter comes up
523 ip1 link add dev wg0 type wireguard
524 n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
525 read _ _ tx_bytes < <(n1 wg show wg0 transfer)
526 [[ $tx_bytes -eq 0 ]]
527 ip1 link set dev wg0 up
528 read _ _ tx_bytes < <(n1 wg show wg0 transfer)
529 [[ $tx_bytes -gt 0 ]]
531 # This should also happen even if the private key is set later
532 ip1 link add dev wg0 type wireguard
533 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.1:1 persistent-keepalive 1
534 read _ _ tx_bytes < <(n1 wg show wg0 transfer)
535 [[ $tx_bytes -eq 0 ]]
536 ip1 link set dev wg0 up
537 read _ _ tx_bytes < <(n1 wg show wg0 transfer)
538 [[ $tx_bytes -eq 0 ]]
539 n1 wg set wg0 private-key <(echo "$key1")
540 read _ _ tx_bytes < <(n1 wg show wg0 transfer)
541 [[ $tx_bytes -gt 0 ]]
542 ip1 link del dev veth1
545 # We test that Netlink/IPC is working properly by doing things that usually cause split responses
546 ip0 link add dev wg0 type wireguard
547 config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
548 for a in {1..255}; do
549 for b in {0..255}; do
550 config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
553 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
555 for ip in $(n0 wg show wg0 allowed-ips); do
560 ip0 link add dev wg0 type wireguard
561 config=( "[Interface]" "PrivateKey=$(wg genkey)" )
563 config+=( "[Peer]" "PublicKey=$(wg genkey)" )
565 config+=( "AllowedIPs=$a.$b.0.0/16" )
568 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
570 while read -r line; do
577 done < <(n0 wg show wg0 allowed-ips)
580 ip0 link add wg0 type wireguard
583 config+=( "[Peer]" "PublicKey=$(wg genkey)" )
585 config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
586 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
587 n0 wg showconf wg0 > /dev/null
591 for i in {1..197}; do
592 allowedips+=( abcd::$i )
596 allowedips="${allowedips[*]}"
598 ip0 link add wg0 type wireguard
599 n0 wg set wg0 peer "$pub1"
600 n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
602 read -r pub allowedips
603 [[ $pub == "$pub1" && $allowedips == "(none)" ]]
604 read -r pub allowedips
605 [[ $pub == "$pub2" ]]
607 for _ in $allowedips; do
611 } < <(n0 wg show wg0 allowed-ips)
614 ! n0 wg show doesnotexist || false
616 ip0 link add wg0 type wireguard
617 n0 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" ]]
620 n0 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)" ]]
623 n0 wg set wg0 peer "$pub2"
624 n0 wg set wg0 private-key <(echo "$key2")
625 [[ $(n0 wg show wg0 public-key) == "$pub2" ]]
626 [[ -z $(n0 wg show wg0 peers) ]]
627 n0 wg set wg0 peer "$pub2"
628 [[ -z $(n0 wg show wg0 peers) ]]
629 n0 wg set wg0 private-key <(echo "$key1")
630 n0 wg set wg0 peer "$pub2"
631 [[ $(n0 wg show wg0 peers) == "$pub2" ]]
632 n0 wg set wg0 private-key <(echo "/${key1:1}")
633 [[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
634 n0 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
635 n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
636 n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
637 n0 wg set wg0 peer "$pub2" allowed-ips ::/0
638 n0 wg set wg0 peer "$pub2" remove
639 for 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
642 [[ -n $(n0 wg show wg0 peers) ]]
643 exec 4< <(n0 ncat -l -u -p 1111)
645 waitncatudp $netns0 $ncat_pid
647 ! read -r -n 1 -t 2 <&4 || false
651 # Ensure that dst_cache references don't outlive netns lifetime
652 ip1 link add dev wg0 type wireguard
653 ip2 link add dev wg0 type wireguard
655 ip1 link add veth1 type veth peer name veth2
656 ip1 link set veth2 netns $netns2
657 ip1 addr add fd00:aa::1/64 dev veth1
658 ip2 addr add fd00:aa::2/64 dev veth2
659 ip1 link set veth1 up
660 ip2 link set veth2 up
661 waitiface $netns1 veth1
662 waitiface $netns2 veth2
663 ip1 -6 route add default dev veth1 via fd00:aa::2
664 ip2 -6 route add default dev veth2 via fd00:aa::1
665 n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
666 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
667 n1 ping6 -c 1 fd00::2
668 pp ip netns delete $netns1
669 pp ip netns delete $netns2
670 pp ip netns add $netns1
671 pp ip netns add $netns2
673 # Ensure there aren't circular reference loops
674 ip1 link add wg1 type wireguard
675 ip2 link add wg2 type wireguard
676 ip1 link set wg1 netns $netns2
677 ip2 link set wg2 netns $netns1
678 pp ip netns delete $netns1
679 pp ip netns delete $netns2
680 pp ip netns add $netns1
681 pp ip netns add $netns2
683 sleep 2 # Wait for cleanup and grace periods
685 while 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]}"
690 for object in "${!objects[@]}"; do
691 if [[ ${objects["$object"]} != *createddestroyed && ${objects["$object"]} != *createdcreateddestroyeddestroyed ]]; then
692 echo "Error: $object: merely ${objects["$object"]}" >&3
696 [[ $alldeleted -eq 1 ]]
697 pretty "" "Objects that were created were also destroyed."