github.com/liloew/wireguard-go@v0.0.0-20220224014633-9cd745e6f114/tests/netns.sh (about)

     1  #!/bin/bash
     2  
     3  # Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
     4  
     5  # This script tests the below topology:
     6  #
     7  # ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐
     8  # │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │
     9  # │                     │   │                                  │   │                     │
    10  # │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│
    11  # ││  wg1   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg2   ││
    12  # │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│
    13  # ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││
    14  # ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││
    15  # │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│
    16  # └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘
    17  #                           └──────────────────────────────────┘
    18  #
    19  # After the topology is prepared we run a series of TCP/UDP iperf3 tests between the
    20  # wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg1
    21  # interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further
    22  # details on how this is accomplished.
    23  
    24  # This code is ported to the WireGuard-Go directly from the kernel project.
    25  #
    26  # Please ensure that you have installed the newest version of the WireGuard
    27  # tools from the WireGuard project and before running these tests as:
    28  #
    29  # ./netns.sh <path to wireguard-go>
    30  
    31  set -e
    32  
    33  exec 3>&1
    34  export WG_HIDE_KEYS=never
    35  netns0="wg-test-$$-0"
    36  netns1="wg-test-$$-1"
    37  netns2="wg-test-$$-2"
    38  program=$1
    39  export LOG_LEVEL="verbose"
    40  
    41  pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
    42  pp() { pretty "" "$*"; "$@"; }
    43  maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
    44  n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
    45  n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
    46  n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
    47  ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
    48  ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
    49  ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
    50  sleep() { read -t "$1" -N 0 || true; }
    51  waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; }
    52  waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
    53  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;"; }
    54  
    55  cleanup() {
    56      set +e
    57      exec 2>/dev/null
    58      printf "$orig_message_cost" > /proc/sys/net/core/message_cost
    59      ip0 link del dev wg1
    60      ip1 link del dev wg1
    61      ip2 link del dev wg1
    62      local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
    63      [[ -n $to_kill ]] && kill $to_kill
    64      pp ip netns del $netns1
    65      pp ip netns del $netns2
    66      pp ip netns del $netns0
    67      exit
    68  }
    69  
    70  orig_message_cost="$(< /proc/sys/net/core/message_cost)"
    71  trap cleanup EXIT
    72  printf 0 > /proc/sys/net/core/message_cost
    73  
    74  ip netns del $netns0 2>/dev/null || true
    75  ip netns del $netns1 2>/dev/null || true
    76  ip netns del $netns2 2>/dev/null || true
    77  pp ip netns add $netns0
    78  pp ip netns add $netns1
    79  pp ip netns add $netns2
    80  ip0 link set up dev lo
    81  
    82  # ip0 link add dev wg1 type wireguard
    83  n0 $program wg1
    84  ip0 link set wg1 netns $netns1
    85  
    86  # ip0 link add dev wg1 type wireguard
    87  n0 $program wg2
    88  ip0 link set wg2 netns $netns2
    89  
    90  key1="$(pp wg genkey)"
    91  key2="$(pp wg genkey)"
    92  pub1="$(pp wg pubkey <<<"$key1")"
    93  pub2="$(pp wg pubkey <<<"$key2")"
    94  psk="$(pp wg genpsk)"
    95  [[ -n $key1 && -n $key2 && -n $psk ]]
    96  
    97  configure_peers() {
    98  
    99      ip1 addr add 192.168.241.1/24 dev wg1
   100      ip1 addr add fd00::1/24 dev wg1
   101  
   102      ip2 addr add 192.168.241.2/24 dev wg2
   103      ip2 addr add fd00::2/24 dev wg2
   104  
   105      n0 wg set wg1 \
   106          private-key <(echo "$key1") \
   107          listen-port 10000 \
   108          peer "$pub2" \
   109              preshared-key <(echo "$psk") \
   110              allowed-ips 192.168.241.2/32,fd00::2/128
   111      n0 wg set wg2 \
   112          private-key <(echo "$key2") \
   113          listen-port 20000 \
   114          peer "$pub1" \
   115              preshared-key <(echo "$psk") \
   116              allowed-ips 192.168.241.1/32,fd00::1/128
   117  
   118      n0 wg showconf wg1
   119      n0 wg showconf wg2
   120  
   121      ip1 link set up dev wg1
   122      ip2 link set up dev wg2
   123      sleep 1
   124  }
   125  configure_peers
   126  
   127  tests() {
   128      # Ping over IPv4
   129      n2 ping -c 10 -f -W 1 192.168.241.1
   130      n1 ping -c 10 -f -W 1 192.168.241.2
   131  
   132      # Ping over IPv6
   133      n2 ping6 -c 10 -f -W 1 fd00::1
   134      n1 ping6 -c 10 -f -W 1 fd00::2
   135  
   136      # TCP over IPv4
   137      n2 iperf3 -s -1 -B 192.168.241.2 &
   138      waitiperf $netns2
   139      n1 iperf3 -Z -n 1G -c 192.168.241.2
   140  
   141      # TCP over IPv6
   142      n1 iperf3 -s -1 -B fd00::1 &
   143      waitiperf $netns1
   144      n2 iperf3 -Z -n 1G -c fd00::1
   145  
   146      # UDP over IPv4
   147      n1 iperf3 -s -1 -B 192.168.241.1 &
   148      waitiperf $netns1
   149      n2 iperf3 -Z -n 1G -b 0 -u -c 192.168.241.1
   150  
   151      # UDP over IPv6
   152      n2 iperf3 -s -1 -B fd00::2 &
   153      waitiperf $netns2
   154      n1 iperf3 -Z -n 1G -b 0 -u -c fd00::2
   155  }
   156  
   157  [[ $(ip1 link show dev wg1) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
   158  big_mtu=$(( 34816 - 1500 + $orig_mtu ))
   159  
   160  # Test using IPv4 as outer transport
   161  n0 wg set wg1 peer "$pub2" endpoint 127.0.0.1:20000
   162  n0 wg set wg2 peer "$pub1" endpoint 127.0.0.1:10000
   163  
   164  # Before calling tests, we first make sure that the stats counters are working
   165  n2 ping -c 10 -f -W 1 192.168.241.1
   166  { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg2)
   167  ip2 -stats link show dev wg2
   168  n0 wg show
   169  [[ $rx_bytes -ge 840 && $tx_bytes -ge 880 && $rx_bytes -lt 2500 && $rx_bytes -lt 2500 ]]
   170  echo "counters working"
   171  tests
   172  ip1 link set wg1 mtu $big_mtu
   173  ip2 link set wg2 mtu $big_mtu
   174  tests
   175  
   176  ip1 link set wg1 mtu $orig_mtu
   177  ip2 link set wg2 mtu $orig_mtu
   178  
   179  # Test using IPv6 as outer transport
   180  n0 wg set wg1 peer "$pub2" endpoint [::1]:20000
   181  n0 wg set wg2 peer "$pub1" endpoint [::1]:10000
   182  tests
   183  ip1 link set wg1 mtu $big_mtu
   184  ip2 link set wg2 mtu $big_mtu
   185  tests
   186  
   187  ip1 link set wg1 mtu $orig_mtu
   188  ip2 link set wg2 mtu $orig_mtu
   189  
   190  # Test using IPv4 that roaming works
   191  ip0 -4 addr del 127.0.0.1/8 dev lo
   192  ip0 -4 addr add 127.212.121.99/8 dev lo
   193  n0 wg set wg1 listen-port 9999
   194  n0 wg set wg1 peer "$pub2" endpoint 127.0.0.1:20000
   195  n1 ping6 -W 1 -c 1 fd00::2
   196  [[ $(n2 wg show wg2 endpoints) == "$pub1	127.212.121.99:9999" ]]
   197  
   198  # Test using IPv6 that roaming works
   199  n1 wg set wg1 listen-port 9998
   200  n1 wg set wg1 peer "$pub2" endpoint [::1]:20000
   201  n1 ping -W 1 -c 1 192.168.241.2
   202  [[ $(n2 wg show wg2 endpoints) == "$pub1	[::1]:9998" ]]
   203  
   204  # Test that crypto-RP filter works
   205  n1 wg set wg1 peer "$pub2" allowed-ips 192.168.241.0/24
   206  exec 4< <(n1 ncat -l -u -p 1111)
   207  nmap_pid=$!
   208  waitncatudp $netns1
   209  n2 ncat -u 192.168.241.1 1111 <<<"X"
   210  read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
   211  kill $nmap_pid
   212  more_specific_key="$(pp wg genkey | pp wg pubkey)"
   213  n0 wg set wg1 peer "$more_specific_key" allowed-ips 192.168.241.2/32
   214  n0 wg set wg2 listen-port 9997
   215  exec 4< <(n1 ncat -l -u -p 1111)
   216  nmap_pid=$!
   217  waitncatudp $netns1
   218  n2 ncat -u 192.168.241.1 1111 <<<"X"
   219  ! read -r -N 1 -t 1 out <&4
   220  kill $nmap_pid
   221  n0 wg set wg1 peer "$more_specific_key" remove
   222  [[ $(n1 wg show wg1 endpoints) == "$pub2	[::1]:9997" ]]
   223  
   224  ip1 link del wg1
   225  ip2 link del wg2
   226  
   227  # Test using NAT. We now change the topology to this:
   228  # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
   229  # │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
   230  # │                                        │    │                                                │     │                                        │
   231  # │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
   232  # │  │ wg1 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg2 │            │
   233  # │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
   234  # │  │192.168.241.1/24│  │192.168.1.100/24││    │    │192.168.1.100/24│    │10.0.0.1/24        │ │     │  │10.0.0.100/24   │ │192.168.241.2/24│ │
   235  # │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
   236  # │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
   237  # └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
   238  
   239  # ip1 link add dev wg1 type wireguard
   240  # ip2 link add dev wg1 type wireguard
   241  
   242  n1 $program wg1
   243  n2 $program wg2
   244  
   245  configure_peers
   246  
   247  ip0 link add vethrc type veth peer name vethc
   248  ip0 link add vethrs type veth peer name veths
   249  ip0 link set vethc netns $netns1
   250  ip0 link set veths netns $netns2
   251  ip0 link set vethrc up
   252  ip0 link set vethrs up
   253  ip0 addr add 192.168.1.1/24 dev vethrc
   254  ip0 addr add 10.0.0.1/24 dev vethrs
   255  ip1 addr add 192.168.1.100/24 dev vethc
   256  ip1 link set vethc up
   257  ip1 route add default via 192.168.1.1
   258  ip2 addr add 10.0.0.100/24 dev veths
   259  ip2 link set veths up
   260  waitiface $netns0 vethrc
   261  waitiface $netns0 vethrs
   262  waitiface $netns1 vethc
   263  waitiface $netns2 veths
   264  
   265  n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
   266  n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
   267  n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
   268  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
   269  
   270  n0 wg set wg1 peer "$pub2" endpoint 10.0.0.100:20000 persistent-keepalive 1
   271  n1 ping -W 1 -c 1 192.168.241.2
   272  n2 ping -W 1 -c 1 192.168.241.1
   273  [[ $(n2 wg show wg2 endpoints) == "$pub1	10.0.0.1:10000" ]]
   274  # Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
   275  pp sleep 3
   276  n2 ping -W 1 -c 1 192.168.241.1
   277  
   278  n0 iptables -t nat -F
   279  ip0 link del vethrc
   280  ip0 link del vethrs
   281  ip1 link del wg1
   282  ip2 link del wg2
   283  
   284  # Test that saddr routing is sticky but not too sticky, changing to this topology:
   285  # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
   286  # │             $ns1 namespace             │    │             $ns2 namespace             │
   287  # │                                        │    │                                        │
   288  # │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
   289  # │  │ wg1 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg2 │            │
   290  # │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
   291  # │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
   292  # │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
   293  # │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
   294  # └────────────────────────────────────────┘    └────────────────────────────────────────┘
   295  
   296  # ip1 link add dev wg1 type wireguard
   297  # ip2 link add dev wg1 type wireguard
   298  n1 $program wg1
   299  n2 $program wg2
   300  
   301  configure_peers
   302  
   303  ip1 link add veth1 type veth peer name veth2
   304  ip1 link set veth2 netns $netns2
   305  n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
   306  n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
   307  n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
   308  
   309  # First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
   310  ip1 addr add 10.0.0.1/24 dev veth1
   311  ip1 addr add fd00:aa::1/96 dev veth1
   312  ip2 addr add 10.0.0.2/24 dev veth2
   313  ip2 addr add fd00:aa::2/96 dev veth2
   314  ip1 link set veth1 up
   315  ip2 link set veth2 up
   316  waitiface $netns1 veth1
   317  waitiface $netns2 veth2
   318  n0 wg set wg1 peer "$pub2" endpoint 10.0.0.2:20000
   319  n1 ping -W 1 -c 1 192.168.241.2
   320  ip1 addr add 10.0.0.10/24 dev veth1
   321  ip1 addr del 10.0.0.1/24 dev veth1
   322  n1 ping -W 1 -c 1 192.168.241.2
   323  n0 wg set wg1 peer "$pub2" endpoint [fd00:aa::2]:20000
   324  n1 ping -W 1 -c 1 192.168.241.2
   325  ip1 addr add fd00:aa::10/96 dev veth1
   326  ip1 addr del fd00:aa::1/96 dev veth1
   327  n1 ping -W 1 -c 1 192.168.241.2
   328  
   329  # Now we show that we can successfully do reply to sender routing
   330  ip1 link set veth1 down
   331  ip2 link set veth2 down
   332  ip1 addr flush dev veth1
   333  ip2 addr flush dev veth2
   334  ip1 addr add 10.0.0.1/24 dev veth1
   335  ip1 addr add 10.0.0.2/24 dev veth1
   336  ip1 addr add fd00:aa::1/96 dev veth1
   337  ip1 addr add fd00:aa::2/96 dev veth1
   338  ip2 addr add 10.0.0.3/24 dev veth2
   339  ip2 addr add fd00:aa::3/96 dev veth2
   340  ip1 link set veth1 up
   341  ip2 link set veth2 up
   342  waitiface $netns1 veth1
   343  waitiface $netns2 veth2
   344  n0 wg set wg2 peer "$pub1" endpoint 10.0.0.1:10000
   345  n2 ping -W 1 -c 1 192.168.241.1
   346  [[ $(n0 wg show wg2 endpoints) == "$pub1	10.0.0.1:10000" ]]
   347  n0 wg set wg2 peer "$pub1" endpoint [fd00:aa::1]:10000
   348  n2 ping -W 1 -c 1 192.168.241.1
   349  [[ $(n0 wg show wg2 endpoints) == "$pub1	[fd00:aa::1]:10000" ]]
   350  n0 wg set wg2 peer "$pub1" endpoint 10.0.0.2:10000
   351  n2 ping -W 1 -c 1 192.168.241.1
   352  [[ $(n0 wg show wg2 endpoints) == "$pub1	10.0.0.2:10000" ]]
   353  n0 wg set wg2 peer "$pub1" endpoint [fd00:aa::2]:10000
   354  n2 ping -W 1 -c 1 192.168.241.1
   355  [[ $(n0 wg show wg2 endpoints) == "$pub1	[fd00:aa::2]:10000" ]]
   356  
   357  ip1 link del veth1
   358  ip1 link del wg1
   359  ip2 link del wg2
   360  
   361  # Test that Netlink/IPC is working properly by doing things that usually cause split responses
   362  
   363  n0 $program wg0
   364  sleep 5
   365  config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
   366  for a in {1..255}; do
   367      for b in {0..255}; do
   368          config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
   369      done
   370  done
   371  n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
   372  i=0
   373  for ip in $(n0 wg show wg0 allowed-ips); do
   374      ((++i))
   375  done
   376  ((i == 255*256*2+1))
   377  ip0 link del wg0
   378  
   379  n0 $program wg0
   380  config=( "[Interface]" "PrivateKey=$(wg genkey)" )
   381  for a in {1..40}; do
   382      config+=( "[Peer]" "PublicKey=$(wg genkey)" )
   383      for b in {1..52}; do
   384          config+=( "AllowedIPs=$a.$b.0.0/16" )
   385      done
   386  done
   387  n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
   388  i=0
   389  while read -r line; do
   390      j=0
   391      for ip in $line; do
   392          ((++j))
   393      done
   394      ((j == 53))
   395      ((++i))
   396  done < <(n0 wg show wg0 allowed-ips)
   397  ((i == 40))
   398  ip0 link del wg0
   399  
   400  n0 $program wg0
   401  config=( )
   402  for i in {1..29}; do
   403      config+=( "[Peer]" "PublicKey=$(wg genkey)" )
   404  done
   405  config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
   406  n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
   407  n0 wg showconf wg0 > /dev/null
   408  ip0 link del wg0
   409  
   410  ! n0 wg show doesnotexist || false
   411  
   412  declare -A objects
   413  while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
   414      [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue
   415      objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
   416  done < /dev/kmsg
   417  alldeleted=1
   418  for object in "${!objects[@]}"; do
   419      if [[ ${objects["$object"]} != *createddestroyed ]]; then
   420          echo "Error: $object: merely ${objects["$object"]}" >&3
   421          alldeleted=0
   422      fi
   423  done
   424  [[ $alldeleted -eq 1 ]]
   425  pretty "" "Objects that were created were also destroyed."