Skip to content

Commit

Permalink
fmuc-mesh-vpn-wireguard: rework wgkex loadbalance
Browse files Browse the repository at this point in the history
  • Loading branch information
grische committed Mar 17, 2024
1 parent ca67656 commit b82299d
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 15 deletions.
13 changes: 10 additions & 3 deletions ffmuc-mesh-vpn-wireguard-vxlan/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This package adds support for WireGuard+VXLAN as Mesh VPN protocol stack as it i
### Dependencies

This relies on [wgkex](https://github.com/freifunkMUC/wgkex), the FFMUC WireGuard key exchange broker running on the configured broker address. The broker programms the gateway to accept the WireGuard key which is transmitted during connection.
Starting with the key exchange API v2, the wgkex broker also returns WireGuard peer data for a gateway selected by the broker, which this package then configures as mesh VPN peer/endpoint. This can be enabled by setting the `loadbalancing` option to `1`.
Starting with the key exchange API v2, the wgkex broker also returns WireGuard peer data for a gateway selected by the broker, which this package then configures as mesh VPN peer/endpoint. This can be enabled by setting the `loadbalancing` option accordingly.

For the health-checks a webserver of some kind needs to listen to `HTTP GET` requests on the gateways.

Expand All @@ -29,8 +29,15 @@ You should use something like the following in the site.conf:
iface = 'wg_mesh_vpn', -- not 'mesh-vpn', this is used for the VXLAN interface
mtu = 1406,
broker = 'broker.ffmuc.net', -- base path of broker, will be combined with API path
loadbalancing = '1' -- controls whether to use the loadbalancing/gateway assignment feature of the broker
peers = { -- only needed if 'loadbalancing = '0''

-- loadbalancing controls whether the client can enable the loadbalancing/gateway assignment feature of the broker
-- on: the client will always use loadbalancing
-- off: the client cannot enable loadbalancing
-- on-by-default: the client can enable/disable loadbalancing and will use loadbalancing by default
-- off-by-default: the client can enable/disable loadbalancing and will not use loadbalancing by default
loadbalancing = 'on-by-default', -- optional

peers = { -- not needed if loadbalancing = 'on'
{
publickey = 'TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g=',
endpoint = 'gw04.ext.ffmuc.net:40011',
Expand Down
7 changes: 6 additions & 1 deletion ffmuc-mesh-vpn-wireguard-vxlan/check_site.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ local function check_peer(k)
need_string(in_domain(extend(k, {'link_address'})))
end

need_table({'mesh_vpn', 'wireguard', 'peers'}, check_peer)
need_number({'mesh_vpn', 'wireguard', 'mtu'})
need_string({'mesh_vpn', 'wireguard', 'broker'})

local loadbalancing = need_one_of({ 'mesh_vpn', 'wireguard', 'loadbalancing' },
{ 'on', 'off', 'on-by-default', 'off-by-default' }, false)
if loadbalancing ~= 'on' then -- peers are not required when loadbalancing is enforced
need_table({'mesh_vpn', 'wireguard', 'peers'}, check_peer)
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ else
exit
fi

get_site_string() {
local path="$1"

lua <<EOF
local site = require 'gluon.site'
print(site.${path}())
EOF
}

get_site_bool() {
local path="$1"

lua <<EOF
local site = require 'gluon.site'
if site.${path}() then
print("true")
else
print("false")
end
EOF
}

interface_linklocal() {
# We generate a predictable v6 address
local macaddr oldIFS
Expand Down Expand Up @@ -64,6 +86,37 @@ force_wan_connection() {
LD_PRELOAD=libpacketmark.so LIBPACKETMARK_MARK=1 gluon-wan "$@"
}

is_loadbalancing_enabled() {
local lb_default
local lb_overwrite
lb_default=$(get_site_string mesh_vpn.wireguard.loadbalancing)

if [[ $lb_default == "on" ]]; then
return 0 # true
elif [[ $lb_default == "off" ]]; then
return 1 # false
fi

# check if an overwrite was specified
if lb_overwrite=$(uci -q get wireguard.mesh_vpn.loadbalancing); then
logger -p info -t checkuplink "Loadbalancing overwrite detected: ${lb_overwrite}"
if [[ $lb_overwrite == "1" ]]; then
return 0 # true
elif [[ $lb_overwrite == "0" ]]; then
return 1 # false
fi
fi

if [[ $lb_default == "on-by-default" ]]; then
return 0 # true
elif [[ $lb_default == "off-by-default" ]]; then
return 1 # false
fi

logger -p err -t checkuplink "Invalid loadbalancing parameter '${lb_default}', assuming 'off'"
return 0
}


mesh_vpn_enabled="$(uci get wireguard.mesh_vpn.enabled)"

Expand Down Expand Up @@ -91,7 +144,7 @@ fi
#We assume we are not connected by default
CONNECTED=0

MESH_VPN_IFACE=$(uci get wireguard.mesh_vpn.iface)
MESH_VPN_IFACE=$(get_site_string mesh_vpn.wireguard.iface)

# Check connectivity to supernode

Expand Down Expand Up @@ -162,12 +215,12 @@ else
fi

# Remove API path suffix if still present in config
WGKEX_BROKER_BASE_PATH="$(uci get wireguard.mesh_vpn.broker | sed 's|/api/v1/wg/key/exchange||')"
WGKEX_BROKER_BASE_PATH="$(get_site_string mesh_vpn.wireguard.broker | sed 's|/api/v1/wg/key/exchange||')"

if [ "$(uci get wireguard.mesh_vpn.loadbalancing)" = "1" ]; then
if is_loadbalancing_enabled; then
# Use /api/v2, get gateway peer details from broker response
WGKEX_BROKER="$PROTO://$WGKEX_BROKER_BASE_PATH/api/v2/wg/key/exchange"
logger -t checkuplink "Contacting wgkex broker $WGKEX_BROKER"
logger -p info -t checkuplink "Loadbalancing enabled. Contacting wgkex broker $WGKEX_BROKER"
if ! WGKEX_DATA=$(force_wan_connection wget -q -O- --post-data='{"domain": "'"$SEGMENT"'","public_key": "'"$PUBLICKEY"'"}' "$WGKEX_BROKER"); then
logger -p err -t checkuplink "Contacting wgkex broker failed, response: $WGKEX_DATA"
exit 1
Expand All @@ -194,7 +247,7 @@ if [ "$(uci get wireguard.mesh_vpn.loadbalancing)" = "1" ]; then
else
# Use /api/v1, get gateway peer details from config
WGKEX_BROKER="$PROTO://$WGKEX_BROKER_BASE_PATH/api/v1/wg/key/exchange"
logger -p info -t checkuplink "Contacting wgkex broker $WGKEX_BROKER"
logger -p info -t checkuplink "Loadbalancing disabled. Contacting wgkex broker $WGKEX_BROKER"
if ! force_wan_connection wget -q -O- --post-data='{"domain": "'"$SEGMENT"'","public_key": "'"$PUBLICKEY"'"}' "$WGKEX_BROKER"; then
logger -p err -t checkuplink "Contacting wgkex broker failed"
exit 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ end
uci:delete_all('wireguard', 'peer', function(peer)
return peer.preserve ~= '1'
end)
-- Clean up previous configuration
uci:delete_all('wireguard', 'wireguard', function(peer)
return peer.preserve ~= '1'
end)

-- Deleted unused configurations from older versions
uci:delete("wireguard", "iface")
uci:delete("wireguard", "limit")
uci:delete("wireguard", "broker")

local mesh_enabled = uci:get_bool('gluon', 'mesh_vpn', 'enabled') -- default
or uci:get_bool('fastd', 'mesh_vpn', 'enabled') --migration
or wg_enabled -- specific config

uci:section("wireguard", "wireguard", "mesh_vpn", {
iface = site.mesh_vpn.wireguard.iface(),
broker = site.mesh_vpn.wireguard.broker(),
enabled = mesh_enabled,
privatekey = privkey,
})

-- TODO: consider removing wireguard.peer and using site directly
for name, peer in pairs(site.mesh_vpn.wireguard.peers()) do
uci:section("wireguard", "peer", "peer_" .. name, {
enabled = true,
Expand Down

0 comments on commit b82299d

Please sign in to comment.