File: router.bash

package info (click to toggle)
mimic 0.7.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,204 kB
  • sloc: ansic: 484,549; sh: 490; makefile: 268
file content (165 lines) | stat: -rwxr-xr-x 5,228 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/bin/bash
#
#         /--------------------------------------\
#         |             Host Network             |
#         |   bridge1                  bridge2   |
#         \-----++-----------------------++------/
# /----------\  ||  /-----------------\  ||  /----------\
# |     veth1+==++==+veth2       veth3+==++==+veth4     |
# |  netns1  |      | netns2 (router) |      |  netns3  |
# \----------/      \-----------------/      \----------/

: "${TEST_NETWORK_ID:=mimicrt}"

br=("br$TEST_NETWORK_ID"{1..2})
netns_internal=("$TEST_NETWORK_ID"{1..3})

veth_internal=("veth$TEST_NETWORK_ID"{1..4})
veth_ipv4_range=(169.254.101.{0,128}/25)
veth_ipv4_internal=(169.254.101.{1,2,129,130}/25)
veth_ipv6_range=(fc11:{1..2}::/64)
veth_ipv6_internal=(fc11:{1..2}::{1..2}/64)

netns=(${netns_internal[0]} ${netns_internal[2]})
veth=(${veth_internal[0]} ${veth_internal[3]})
veth_ipv4=(${veth_ipv4_internal[0]} ${veth_ipv4_internal[3]})
veth_ipv6=(${veth_ipv6_internal[0]} ${veth_ipv6_internal[3]})

wg_port=(1101{1..2})
wg_ipv4_range=169.254.201.0/24
wg_ipv4=(169.254.201.{1..2}/24)
wg_ipv6_range=fc21::/64
wg_ipv6=(fc21::{1..2}/64)

_curdir=$(dirname $(realpath "${BASH_SOURCE[0]}"))
source "$_curdir/../util.bash"

router_env_setup() {
  for _i in "$@"; do
    case "$_i" in
    # --mtu=*) local mtu="${_i#*=}" ;;
    # --no-offload) local no_offload=true ;;
    --wg) local wg=1 ;;
    --wg-v4) local wg_ip_kind=v4 ;;
    --wg-v6) local wg_ip_kind=v6 ;;
    --wg-mtu=*) local wg_mtu="${_i#*=}" ;;
    *) ;;
    esac
  done

  for _netns in ${netns_internal[@]}; do
    ip netns add $_netns
    ip netns exec $_netns sysctl -w net.ipv4.conf.all.forwarding=1
    ip netns exec $_netns sysctl -w net.ipv6.conf.all.forwarding=1
  done

  for _i in {0..1}; do
    ip link add ${br[$_i]} type bridge
    ip link set ${br[$_i]} up

    for _j in {0..1}; do
      local _n=$((_i * 2 + _j))                    # veth index
      local _netns=${netns_internal[$((_i + _j))]} # netns where the veth should be in

      ip link add ${veth_internal[$_n]} type veth peer ${veth_internal[$_n]} netns $_netns
      ip link set ${veth_internal[$_n]} master ${br[$_i]}

      ip -n $_netns addr add dev ${veth_internal[$_n]} ${veth_ipv4_internal[$_n]}
      ip -n $_netns addr add dev ${veth_internal[$_n]} ${veth_ipv6_internal[$_n]}

      ip link set ${veth_internal[$_n]} up
      ip -n $_netns link set lo up
      ip -n $_netns link set ${veth_internal[$_n]} up
    done
  done

  sleep 3 # IPv6 addresses seem to need some warmup

  # This is a bit messy, but it basically sets correct route of the other side
  # through the "router" netns
  ip -n ${netns_internal[0]} route add ${veth_ipv4_range[1]} \
    via $(strip_ip_cidr ${veth_ipv4_internal[1]}) \
    src $(strip_ip_cidr ${veth_ipv4_internal[0]}) \
    dev ${veth_internal[0]}
  ip -n ${netns_internal[2]} route add ${veth_ipv4_range[0]} \
    via $(strip_ip_cidr ${veth_ipv4_internal[2]}) \
    src $(strip_ip_cidr ${veth_ipv4_internal[3]}) \
    dev ${veth_internal[3]}
  ip -6 -n ${netns_internal[0]} route add ${veth_ipv6_range[1]} \
    via $(strip_ip_cidr ${veth_ipv6_internal[1]}) \
    src $(strip_ip_cidr ${veth_ipv6_internal[0]}) \
    dev ${veth_internal[0]}
  ip -6 -n ${netns_internal[2]} route add ${veth_ipv6_range[0]} \
    via $(strip_ip_cidr ${veth_ipv6_internal[2]}) \
    src $(strip_ip_cidr ${veth_ipv6_internal[3]}) \
    dev ${veth_internal[3]}

  # Enable conntrack in router
  ip netns exec ${netns_internal[1]} nft -f - <<EOF
table inet filter {
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state new,established,related accept
    ip protocol tcp ct state invalid reject with tcp reset
  }
}
EOF

  if [ -n "$wg" ]; then
    local _priv_key=($(wg genkey) $(wg genkey))
    for _i in {0..1}; do
      ip -n ${netns[$_i]} link add wg-${veth[$_i]} type wireguard
      ip -n ${netns[$_i]} addr add dev wg-${veth[$_i]} ${wg_ipv4[$_i]}
      ip -n ${netns[$_i]} addr add dev wg-${veth[$_i]} ${wg_ipv6[$_i]}

      ip netns exec ${netns[$_i]} wg set wg-${veth[$_i]} \
        listen-port ${wg_port[$_i]} \
        private-key <(echo ${_priv_key[$_i]})

      for _j in {0..1}; do
        if [ $_i -eq $_j ]; then continue; fi
        local _endpoint
        if [ "$wg_ip_kind" = v6 ]; then
          _endpoint=\[$(strip_ip_cidr ${veth_ipv6[$_j]})\]
        else
          _endpoint=$(strip_ip_cidr ${veth_ipv4[$_j]})
        fi
        ip netns exec ${netns[$_i]} wg set wg-${veth[$_i]} \
          peer $(echo ${_priv_key[$_j]} | wg pubkey) \
          allowed-ips ${wg_ipv4_range},${wg_ipv6_range} \
          endpoint $_endpoint:${wg_port[$_j]}
      done

      [ -z "$wg_mtu" ] || ip -n ${netns[$_i]} link set wg-${veth[$_i]} mtu "$wg_mtu"
      ip -n ${netns[$_i]} link set wg-${veth[$_i]} up
    done
  fi
}

router_env_cleanup() {
  set +e
  for _br in ${br[@]}; do
    ip link del $_br
  done
  for _netns in ${netns_internal[@]}; do
    ip netns del $_netns
  done
}

if [ "${BASH_SOURCE[0]}" = "$0" ]; then
  set -e
  case "$1" in
  setup)
    shift
    router_env_setup $@
    ;;
  clean)
    shift
    router_env_cleanup $@
    ;;
  *)
    >&2 echo "expected 'setup' or 'clean'"
    exit 1
    ;;
  esac
fi