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