Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
0005 #
0006 # This script tests the below topology:
0007 #
0008 # ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐
0009 # │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │
0010 # │                     │   │                                  │   │                     │
0011 # │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│
0012 # ││  wg0   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg0   ││
0013 # │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│
0014 # ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││
0015 # ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││
0016 # │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│
0017 # └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘
0018 #                           └──────────────────────────────────┘
0019 #
0020 # After the topology is prepared we run a series of TCP/UDP iperf3 tests between the
0021 # wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0
0022 # interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further
0023 # details on how this is accomplished.
0024 set -e
0025 shopt -s extglob
0026 
0027 exec 3>&1
0028 export LANG=C
0029 export WG_HIDE_KEYS=never
0030 NPROC=( /sys/devices/system/cpu/cpu+([0-9]) ); NPROC=${#NPROC[@]}
0031 netns0="wg-test-$$-0"
0032 netns1="wg-test-$$-1"
0033 netns2="wg-test-$$-2"
0034 pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
0035 pp() { pretty "" "$*"; "$@"; }
0036 maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
0037 n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
0038 n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
0039 n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
0040 ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
0041 ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
0042 ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
0043 sleep() { read -t "$1" -N 1 || true; }
0044 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; }
0045 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; }
0046 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;"; }
0047 
0048 cleanup() {
0049         set +e
0050         exec 2>/dev/null
0051         printf "$orig_message_cost" > /proc/sys/net/core/message_cost
0052         ip0 link del dev wg0
0053         ip0 link del dev wg1
0054         ip1 link del dev wg0
0055         ip1 link del dev wg1
0056         ip2 link del dev wg0
0057         ip2 link del dev wg1
0058         local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
0059         [[ -n $to_kill ]] && kill $to_kill
0060         pp ip netns del $netns1
0061         pp ip netns del $netns2
0062         pp ip netns del $netns0
0063         exit
0064 }
0065 
0066 orig_message_cost="$(< /proc/sys/net/core/message_cost)"
0067 trap cleanup EXIT
0068 printf 0 > /proc/sys/net/core/message_cost
0069 
0070 ip netns del $netns0 2>/dev/null || true
0071 ip netns del $netns1 2>/dev/null || true
0072 ip netns del $netns2 2>/dev/null || true
0073 pp ip netns add $netns0
0074 pp ip netns add $netns1
0075 pp ip netns add $netns2
0076 ip0 link set up dev lo
0077 
0078 ip0 link add dev wg0 type wireguard
0079 ip0 link set wg0 netns $netns1
0080 ip0 link add dev wg0 type wireguard
0081 ip0 link set wg0 netns $netns2
0082 key1="$(pp wg genkey)"
0083 key2="$(pp wg genkey)"
0084 key3="$(pp wg genkey)"
0085 key4="$(pp wg genkey)"
0086 pub1="$(pp wg pubkey <<<"$key1")"
0087 pub2="$(pp wg pubkey <<<"$key2")"
0088 pub3="$(pp wg pubkey <<<"$key3")"
0089 pub4="$(pp wg pubkey <<<"$key4")"
0090 psk="$(pp wg genpsk)"
0091 [[ -n $key1 && -n $key2 && -n $psk ]]
0092 
0093 configure_peers() {
0094         ip1 addr add 192.168.241.1/24 dev wg0
0095         ip1 addr add fd00::1/112 dev wg0
0096 
0097         ip2 addr add 192.168.241.2/24 dev wg0
0098         ip2 addr add fd00::2/112 dev wg0
0099 
0100         n1 wg set wg0 \
0101                 private-key <(echo "$key1") \
0102                 listen-port 1 \
0103                 peer "$pub2" \
0104                         preshared-key <(echo "$psk") \
0105                         allowed-ips 192.168.241.2/32,fd00::2/128
0106         n2 wg set wg0 \
0107                 private-key <(echo "$key2") \
0108                 listen-port 2 \
0109                 peer "$pub1" \
0110                         preshared-key <(echo "$psk") \
0111                         allowed-ips 192.168.241.1/32,fd00::1/128
0112 
0113         ip1 link set up dev wg0
0114         ip2 link set up dev wg0
0115 }
0116 configure_peers
0117 
0118 tests() {
0119         # Ping over IPv4
0120         n2 ping -c 10 -f -W 1 192.168.241.1
0121         n1 ping -c 10 -f -W 1 192.168.241.2
0122 
0123         # Ping over IPv6
0124         n2 ping6 -c 10 -f -W 1 fd00::1
0125         n1 ping6 -c 10 -f -W 1 fd00::2
0126 
0127         # TCP over IPv4
0128         n2 iperf3 -s -1 -B 192.168.241.2 &
0129         waitiperf $netns2 $!
0130         n1 iperf3 -Z -t 3 -c 192.168.241.2
0131 
0132         # TCP over IPv6
0133         n1 iperf3 -s -1 -B fd00::1 &
0134         waitiperf $netns1 $!
0135         n2 iperf3 -Z -t 3 -c fd00::1
0136 
0137         # UDP over IPv4
0138         n1 iperf3 -s -1 -B 192.168.241.1 &
0139         waitiperf $netns1 $!
0140         n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
0141 
0142         # UDP over IPv6
0143         n2 iperf3 -s -1 -B fd00::2 &
0144         waitiperf $netns2 $!
0145         n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
0146 
0147         # TCP over IPv4, in parallel
0148         local pids=( ) i
0149         for ((i=0; i < NPROC; ++i)) do
0150                 n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 &
0151                 pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i ))
0152         done
0153         for ((i=0; i < NPROC; ++i)) do
0154                 n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
0155         done
0156         wait "${pids[@]}"
0157 }
0158 
0159 [[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
0160 big_mtu=$(( 34816 - 1500 + $orig_mtu ))
0161 
0162 # Test using IPv4 as outer transport
0163 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
0164 n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
0165 # Before calling tests, we first make sure that the stats counters and timestamper are working
0166 n2 ping -c 10 -f -W 1 192.168.241.1
0167 { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
0168 (( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
0169 { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
0170 (( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
0171 read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
0172 (( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
0173 read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
0174 (( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
0175 read _ timestamp < <(n1 wg show wg0 latest-handshakes)
0176 (( timestamp != 0 ))
0177 
0178 tests
0179 ip1 link set wg0 mtu $big_mtu
0180 ip2 link set wg0 mtu $big_mtu
0181 tests
0182 
0183 ip1 link set wg0 mtu $orig_mtu
0184 ip2 link set wg0 mtu $orig_mtu
0185 
0186 # Test using IPv6 as outer transport
0187 n1 wg set wg0 peer "$pub2" endpoint [::1]:2
0188 n2 wg set wg0 peer "$pub1" endpoint [::1]:1
0189 tests
0190 ip1 link set wg0 mtu $big_mtu
0191 ip2 link set wg0 mtu $big_mtu
0192 tests
0193 
0194 # Test that route MTUs work with the padding
0195 ip1 link set wg0 mtu 1300
0196 ip2 link set wg0 mtu 1300
0197 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
0198 n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
0199 n0 iptables -A INPUT -m length --length 1360 -j DROP
0200 n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
0201 n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
0202 n2 ping -c 1 -W 1 -s 1269 192.168.241.1
0203 n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
0204 n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
0205 n0 iptables -F INPUT
0206 
0207 ip1 link set wg0 mtu $orig_mtu
0208 ip2 link set wg0 mtu $orig_mtu
0209 
0210 # Test using IPv4 that roaming works
0211 ip0 -4 addr del 127.0.0.1/8 dev lo
0212 ip0 -4 addr add 127.212.121.99/8 dev lo
0213 n1 wg set wg0 listen-port 9999
0214 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
0215 n1 ping6 -W 1 -c 1 fd00::2
0216 [[ $(n2 wg show wg0 endpoints) == "$pub1        127.212.121.99:9999" ]]
0217 
0218 # Test using IPv6 that roaming works
0219 n1 wg set wg0 listen-port 9998
0220 n1 wg set wg0 peer "$pub2" endpoint [::1]:2
0221 n1 ping -W 1 -c 1 192.168.241.2
0222 [[ $(n2 wg show wg0 endpoints) == "$pub1        [::1]:9998" ]]
0223 
0224 # Test that crypto-RP filter works
0225 n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
0226 exec 4< <(n1 ncat -l -u -p 1111)
0227 ncat_pid=$!
0228 waitncatudp $netns1 $ncat_pid
0229 n2 ncat -u 192.168.241.1 1111 <<<"X"
0230 read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
0231 kill $ncat_pid
0232 more_specific_key="$(pp wg genkey | pp wg pubkey)"
0233 n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
0234 n2 wg set wg0 listen-port 9997
0235 exec 4< <(n1 ncat -l -u -p 1111)
0236 ncat_pid=$!
0237 waitncatudp $netns1 $ncat_pid
0238 n2 ncat -u 192.168.241.1 1111 <<<"X"
0239 ! read -r -N 1 -t 1 out <&4 || false
0240 kill $ncat_pid
0241 n1 wg set wg0 peer "$more_specific_key" remove
0242 [[ $(n1 wg show wg0 endpoints) == "$pub2        [::1]:9997" ]]
0243 
0244 # Test that we can change private keys keys and immediately handshake
0245 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
0246 n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
0247 n1 ping -W 1 -c 1 192.168.241.2
0248 n1 wg set wg0 private-key <(echo "$key3")
0249 n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
0250 n1 ping -W 1 -c 1 192.168.241.2
0251 n2 wg set wg0 peer "$pub3" remove
0252 
0253 # Test that we can route wg through wg
0254 ip1 addr flush dev wg0
0255 ip2 addr flush dev wg0
0256 ip1 addr add fd00::5:1/112 dev wg0
0257 ip2 addr add fd00::5:2/112 dev wg0
0258 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
0259 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
0260 ip1 link add wg1 type wireguard
0261 ip2 link add wg1 type wireguard
0262 ip1 addr add 192.168.241.1/24 dev wg1
0263 ip1 addr add fd00::1/112 dev wg1
0264 ip2 addr add 192.168.241.2/24 dev wg1
0265 ip2 addr add fd00::2/112 dev wg1
0266 ip1 link set mtu 1340 up dev wg1
0267 ip2 link set mtu 1340 up dev wg1
0268 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
0269 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
0270 tests
0271 # Try to set up a routing loop between the two namespaces
0272 ip1 link set netns $netns0 dev wg1
0273 ip0 addr add 192.168.241.1/24 dev wg1
0274 ip0 link set up dev wg1
0275 n0 ping -W 1 -c 1 192.168.241.2
0276 n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
0277 ip2 link del wg0
0278 ip2 link del wg1
0279 read _ _ tx_bytes_before < <(n0 wg show wg1 transfer)
0280 ! n0 ping -W 1 -c 10 -f 192.168.241.2 || false
0281 sleep 1
0282 read _ _ tx_bytes_after < <(n0 wg show wg1 transfer)
0283 if ! (( tx_bytes_after - tx_bytes_before < 70000 )); then
0284         errstart=$'\x1b[37m\x1b[41m\x1b[1m'
0285         errend=$'\x1b[0m'
0286         echo "${errstart}                                                ${errend}"
0287         echo "${errstart}                   E  R  R  O  R                ${errend}"
0288         echo "${errstart}                                                ${errend}"
0289         echo "${errstart} This architecture does not do the right thing  ${errend}"
0290         echo "${errstart} with cross-namespace routing loops. This test  ${errend}"
0291         echo "${errstart} has thus technically failed but, as this issue ${errend}"
0292         echo "${errstart} is as yet unsolved, these tests will continue  ${errend}"
0293         echo "${errstart} onward. :(                                     ${errend}"
0294         echo "${errstart}                                                ${errend}"
0295 fi
0296 
0297 ip0 link del wg1
0298 ip1 link del wg0
0299 
0300 # Test using NAT. We now change the topology to this:
0301 # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
0302 # │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
0303 # │                                        │    │                                                │     │                                        │
0304 # │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
0305 # │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
0306 # │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
0307 # │  │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│ │
0308 # │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
0309 # │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
0310 # └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
0311 
0312 ip1 link add dev wg0 type wireguard
0313 ip2 link add dev wg0 type wireguard
0314 configure_peers
0315 
0316 ip0 link add vethrc type veth peer name vethc
0317 ip0 link add vethrs type veth peer name veths
0318 ip0 link set vethc netns $netns1
0319 ip0 link set veths netns $netns2
0320 ip0 link set vethrc up
0321 ip0 link set vethrs up
0322 ip0 addr add 192.168.1.1/24 dev vethrc
0323 ip0 addr add 10.0.0.1/24 dev vethrs
0324 ip1 addr add 192.168.1.100/24 dev vethc
0325 ip1 link set vethc up
0326 ip1 route add default via 192.168.1.1
0327 ip2 addr add 10.0.0.100/24 dev veths
0328 ip2 link set veths up
0329 waitiface $netns0 vethrc
0330 waitiface $netns0 vethrs
0331 waitiface $netns1 vethc
0332 waitiface $netns2 veths
0333 
0334 n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
0335 n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
0336 n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
0337 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
0338 
0339 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
0340 n1 ping -W 1 -c 1 192.168.241.2
0341 n2 ping -W 1 -c 1 192.168.241.1
0342 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.0.0.1:1" ]]
0343 # Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
0344 pp sleep 3
0345 n2 ping -W 1 -c 1 192.168.241.1
0346 n1 wg set wg0 peer "$pub2" persistent-keepalive 0
0347 
0348 # Test that sk_bound_dev_if works
0349 n1 ping -I wg0 -c 1 -W 1 192.168.241.2
0350 # What about when the mark changes and the packet must be rerouted?
0351 n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
0352 n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
0353 n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
0354 n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
0355 
0356 # Test that onion routing works, even when it loops
0357 n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
0358 ip1 addr add 192.168.242.1/24 dev wg0
0359 ip2 link add wg1 type wireguard
0360 ip2 addr add 192.168.242.2/24 dev wg1
0361 n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
0362 ip2 link set wg1 up
0363 n1 ping -W 1 -c 1 192.168.242.2
0364 ip2 link del wg1
0365 n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
0366 ! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
0367 n1 wg set wg0 peer "$pub3" remove
0368 ip1 addr del 192.168.242.1/24 dev wg0
0369 
0370 # Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
0371 ip1 -6 addr add fc00::9/96 dev vethc
0372 ip1 -6 route add default via fc00::1
0373 ip2 -4 addr add 192.168.99.7/32 dev wg0
0374 ip2 -6 addr add abab::1111/128 dev wg0
0375 n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
0376 ip1 -6 route add default dev wg0 table 51820
0377 ip1 -6 rule add not fwmark 51820 table 51820
0378 ip1 -6 rule add table main suppress_prefixlength 0
0379 ip1 -4 route add default dev wg0 table 51820
0380 ip1 -4 rule add not fwmark 51820 table 51820
0381 ip1 -4 rule add table main suppress_prefixlength 0
0382 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter'
0383 # Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
0384 n1 ping -W 1 -c 100 -f 192.168.99.7
0385 n1 ping -W 1 -c 100 -f abab::1111
0386 
0387 # Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
0388 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
0389 n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
0390 n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
0391 ip0 -4 route add 192.168.241.1 via 10.0.0.100
0392 n2 wg set wg0 peer "$pub1" remove
0393 [[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
0394 
0395 n0 iptables -t nat -F
0396 n0 iptables -t filter -F
0397 n2 iptables -t nat -F
0398 ip0 link del vethrc
0399 ip0 link del vethrs
0400 ip1 link del wg0
0401 ip2 link del wg0
0402 
0403 # Test that saddr routing is sticky but not too sticky, changing to this topology:
0404 # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
0405 # │             $ns1 namespace             │    │             $ns2 namespace             │
0406 # │                                        │    │                                        │
0407 # │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
0408 # │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
0409 # │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
0410 # │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
0411 # │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
0412 # │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
0413 # └────────────────────────────────────────┘    └────────────────────────────────────────┘
0414 
0415 ip1 link add dev wg0 type wireguard
0416 ip2 link add dev wg0 type wireguard
0417 configure_peers
0418 ip1 link add veth1 type veth peer name veth2
0419 ip1 link set veth2 netns $netns2
0420 n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
0421 n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
0422 n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
0423 n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
0424 n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
0425 
0426 # First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
0427 ip1 addr add 10.0.0.1/24 dev veth1
0428 ip1 addr add fd00:aa::1/96 dev veth1
0429 ip2 addr add 10.0.0.2/24 dev veth2
0430 ip2 addr add fd00:aa::2/96 dev veth2
0431 ip1 link set veth1 up
0432 ip2 link set veth2 up
0433 waitiface $netns1 veth1
0434 waitiface $netns2 veth2
0435 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
0436 n1 ping -W 1 -c 1 192.168.241.2
0437 ip1 addr add 10.0.0.10/24 dev veth1
0438 ip1 addr del 10.0.0.1/24 dev veth1
0439 n1 ping -W 1 -c 1 192.168.241.2
0440 n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
0441 n1 ping -W 1 -c 1 192.168.241.2
0442 ip1 addr add fd00:aa::10/96 dev veth1
0443 ip1 addr del fd00:aa::1/96 dev veth1
0444 n1 ping -W 1 -c 1 192.168.241.2
0445 
0446 # Now we show that we can successfully do reply to sender routing
0447 ip1 link set veth1 down
0448 ip2 link set veth2 down
0449 ip1 addr flush dev veth1
0450 ip2 addr flush dev veth2
0451 ip1 addr add 10.0.0.1/24 dev veth1
0452 ip1 addr add 10.0.0.2/24 dev veth1
0453 ip1 addr add fd00:aa::1/96 dev veth1
0454 ip1 addr add fd00:aa::2/96 dev veth1
0455 ip2 addr add 10.0.0.3/24 dev veth2
0456 ip2 addr add fd00:aa::3/96 dev veth2
0457 ip1 link set veth1 up
0458 ip2 link set veth2 up
0459 waitiface $netns1 veth1
0460 waitiface $netns2 veth2
0461 n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
0462 n2 ping -W 1 -c 1 192.168.241.1
0463 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.0.0.1:1" ]]
0464 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
0465 n2 ping -W 1 -c 1 192.168.241.1
0466 [[ $(n2 wg show wg0 endpoints) == "$pub1        [fd00:aa::1]:1" ]]
0467 n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
0468 n2 ping -W 1 -c 1 192.168.241.1
0469 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.0.0.2:1" ]]
0470 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
0471 n2 ping -W 1 -c 1 192.168.241.1
0472 [[ $(n2 wg show wg0 endpoints) == "$pub1        [fd00:aa::2]:1" ]]
0473 
0474 # What happens if the inbound destination address belongs to a different interface as the default route?
0475 ip1 link add dummy0 type dummy
0476 ip1 addr add 10.50.0.1/24 dev dummy0
0477 ip1 link set dummy0 up
0478 ip2 route add 10.50.0.0/24 dev veth2
0479 n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
0480 n2 ping -W 1 -c 1 192.168.241.1
0481 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.50.0.1:1" ]]
0482 
0483 ip1 link del dummy0
0484 ip1 addr flush dev veth1
0485 ip2 addr flush dev veth2
0486 ip1 route flush dev veth1
0487 ip2 route flush dev veth2
0488 
0489 # Now we see what happens if another interface route takes precedence over an ongoing one
0490 ip1 link add veth3 type veth peer name veth4
0491 ip1 link set veth4 netns $netns2
0492 ip1 addr add 10.0.0.1/24 dev veth1
0493 ip2 addr add 10.0.0.2/24 dev veth2
0494 ip1 addr add 10.0.0.3/24 dev veth3
0495 ip1 link set veth1 up
0496 ip2 link set veth2 up
0497 ip1 link set veth3 up
0498 ip2 link set veth4 up
0499 waitiface $netns1 veth1
0500 waitiface $netns2 veth2
0501 waitiface $netns1 veth3
0502 waitiface $netns2 veth4
0503 ip1 route flush dev veth1
0504 ip1 route flush dev veth3
0505 ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
0506 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
0507 n1 ping -W 1 -c 1 192.168.241.2
0508 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.0.0.1:1" ]]
0509 ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
0510 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
0511 n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
0512 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
0513 n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
0514 n1 ping -W 1 -c 1 192.168.241.2
0515 [[ $(n2 wg show wg0 endpoints) == "$pub1        10.0.0.3:1" ]]
0516 
0517 ip1 link del veth1
0518 ip1 link del veth3
0519 ip1 link del wg0
0520 ip2 link del wg0
0521 
0522 # We test that Netlink/IPC is working properly by doing things that usually cause split responses
0523 ip0 link add dev wg0 type wireguard
0524 config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
0525 for a in {1..255}; do
0526         for b in {0..255}; do
0527                 config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
0528         done
0529 done
0530 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
0531 i=0
0532 for ip in $(n0 wg show wg0 allowed-ips); do
0533         ((++i))
0534 done
0535 ((i == 255*256*2+1))
0536 ip0 link del wg0
0537 ip0 link add dev wg0 type wireguard
0538 config=( "[Interface]" "PrivateKey=$(wg genkey)" )
0539 for a in {1..40}; do
0540         config+=( "[Peer]" "PublicKey=$(wg genkey)" )
0541         for b in {1..52}; do
0542                 config+=( "AllowedIPs=$a.$b.0.0/16" )
0543         done
0544 done
0545 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
0546 i=0
0547 while read -r line; do
0548         j=0
0549         for ip in $line; do
0550                 ((++j))
0551         done
0552         ((j == 53))
0553         ((++i))
0554 done < <(n0 wg show wg0 allowed-ips)
0555 ((i == 40))
0556 ip0 link del wg0
0557 ip0 link add wg0 type wireguard
0558 config=( )
0559 for i in {1..29}; do
0560         config+=( "[Peer]" "PublicKey=$(wg genkey)" )
0561 done
0562 config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
0563 n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
0564 n0 wg showconf wg0 > /dev/null
0565 ip0 link del wg0
0566 
0567 allowedips=( )
0568 for i in {1..197}; do
0569         allowedips+=( abcd::$i )
0570 done
0571 saved_ifs="$IFS"
0572 IFS=,
0573 allowedips="${allowedips[*]}"
0574 IFS="$saved_ifs"
0575 ip0 link add wg0 type wireguard
0576 n0 wg set wg0 peer "$pub1"
0577 n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
0578 {
0579         read -r pub allowedips
0580         [[ $pub == "$pub1" && $allowedips == "(none)" ]]
0581         read -r pub allowedips
0582         [[ $pub == "$pub2" ]]
0583         i=0
0584         for _ in $allowedips; do
0585                 ((++i))
0586         done
0587         ((i == 197))
0588 } < <(n0 wg show wg0 allowed-ips)
0589 ip0 link del wg0
0590 
0591 ! n0 wg show doesnotexist || false
0592 
0593 ip0 link add wg0 type wireguard
0594 n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
0595 [[ $(n0 wg show wg0 private-key) == "$key1" ]]
0596 [[ $(n0 wg show wg0 preshared-keys) == "$pub2   $psk" ]]
0597 n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
0598 [[ $(n0 wg show wg0 private-key) == "(none)" ]]
0599 [[ $(n0 wg show wg0 preshared-keys) == "$pub2   (none)" ]]
0600 n0 wg set wg0 peer "$pub2"
0601 n0 wg set wg0 private-key <(echo "$key2")
0602 [[ $(n0 wg show wg0 public-key) == "$pub2" ]]
0603 [[ -z $(n0 wg show wg0 peers) ]]
0604 n0 wg set wg0 peer "$pub2"
0605 [[ -z $(n0 wg show wg0 peers) ]]
0606 n0 wg set wg0 private-key <(echo "$key1")
0607 n0 wg set wg0 peer "$pub2"
0608 [[ $(n0 wg show wg0 peers) == "$pub2" ]]
0609 n0 wg set wg0 private-key <(echo "/${key1:1}")
0610 [[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
0611 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
0612 n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
0613 n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
0614 n0 wg set wg0 peer "$pub2" allowed-ips ::/0
0615 n0 wg set wg0 peer "$pub2" remove
0616 for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
0617         n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
0618 done
0619 [[ -n $(n0 wg show wg0 peers) ]]
0620 exec 4< <(n0 ncat -l -u -p 1111)
0621 ncat_pid=$!
0622 waitncatudp $netns0 $ncat_pid
0623 ip0 link set wg0 up
0624 ! read -r -n 1 -t 2 <&4 || false
0625 kill $ncat_pid
0626 ip0 link del wg0
0627 
0628 # Ensure that dst_cache references don't outlive netns lifetime
0629 ip1 link add dev wg0 type wireguard
0630 ip2 link add dev wg0 type wireguard
0631 configure_peers
0632 ip1 link add veth1 type veth peer name veth2
0633 ip1 link set veth2 netns $netns2
0634 ip1 addr add fd00:aa::1/64 dev veth1
0635 ip2 addr add fd00:aa::2/64 dev veth2
0636 ip1 link set veth1 up
0637 ip2 link set veth2 up
0638 waitiface $netns1 veth1
0639 waitiface $netns2 veth2
0640 ip1 -6 route add default dev veth1 via fd00:aa::2
0641 ip2 -6 route add default dev veth2 via fd00:aa::1
0642 n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
0643 n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
0644 n1 ping6 -c 1 fd00::2
0645 pp ip netns delete $netns1
0646 pp ip netns delete $netns2
0647 pp ip netns add $netns1
0648 pp ip netns add $netns2
0649 
0650 # Ensure there aren't circular reference loops
0651 ip1 link add wg1 type wireguard
0652 ip2 link add wg2 type wireguard
0653 ip1 link set wg1 netns $netns2
0654 ip2 link set wg2 netns $netns1
0655 pp ip netns delete $netns1
0656 pp ip netns delete $netns2
0657 pp ip netns add $netns1
0658 pp ip netns add $netns2
0659 
0660 sleep 2 # Wait for cleanup and grace periods
0661 declare -A objects
0662 while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
0663         [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
0664         objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
0665 done < /dev/kmsg
0666 alldeleted=1
0667 for object in "${!objects[@]}"; do
0668         if [[ ${objects["$object"]} != *createddestroyed && ${objects["$object"]} != *createdcreateddestroyeddestroyed ]]; then
0669                 echo "Error: $object: merely ${objects["$object"]}" >&3
0670                 alldeleted=0
0671         fi
0672 done
0673 [[ $alldeleted -eq 1 ]]
0674 pretty "" "Objects that were created were also destroyed."