Skip to content
Snippets Groups Projects
Unverified Commit 8d7065be authored by David Bauer's avatar David Bauer Committed by GitHub
Browse files

ffac-mesh-vpn-wireguard-openwrt19: drop package (#83)


The master branch of the community-packages repo does not target OpenWrt
19.07 based Gluon versions.

We should not contain packages for such old and potentially insecure
OpenWrt releases.

Signed-off-by: default avatarDavid Bauer <mail@david-bauer.net>
parent 661f553c
Branches
No related tags found
No related merge requests found
Showing with 0 additions and 331 deletions
# SPDX-FileCopyrightText: 2023 Florian Maurer (FFAC), Annika Wickert (FFMUC)
# SPDX-License-Identifier: GPL-2.0-or-later
include $(TOPDIR)/rules.mk
PKG_NAME:=ffac-mesh-vpn-wireguard-openwrt19
PKG_VERSION:=1
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0-or-later
include $(TOPDIR)/../package/gluon.mk
define Package/$(PKG_NAME)
TITLE:=Support for connecting meshes via wireguard
DEPENDS:=+gluon-mesh-vpn-core +micrond +kmod-wireguard +wireguard-tools +ip-full
endef
define Package/$(PKG_NAME)/install
$(CP) ./files/* $(1)/
$(CP) ./luasrc/* $(1)/
./gluonShellDiet.sh $(1)/lib/gluon/gluon-mesh-wireguard-vxlan/checkuplink
endef
$(eval $(call BuildPackageGluon,$(PKG_NAME)))
# ffac-mesh-vpn-wireguard-openwrt19
You can use this package for connecting with wireguard to a upstream gluon-mesh-vpn-wireguard compatible network.
When upgrading to the upstream version of mesh-vpn-wireguard, the same wireguard privatekey is used.
A special thanks to Annika Wickert @awlx who first developed ffmuc-mesh-vpn-wireguard-vxlan
This version is compatible with Gluon v2021.1.x and later, but it is highly advertised to use gluon-mesh-vpn-wireguard on v2022.1.x and later.
You should use something like the following in the site.conf:
**Note that the peers are not named in contrast to the upstream package version**
```
mesh_vpn = {
mtu = 1400,
wireguard = {
enabled = '1',
iface = 'mesh-vpn',
broker = 'wg-broker.freifunk-aachen.de/api/add_key',
peers = {
{
public_key ='N9uF5Gg1B5AqWrE9IuvDgzmQePhqhb8Em/HrRpAdnlY=',
endpoint ='ffkwsn01.freifunk-koenigswinter.de:30020',
link_address = 'fe80::f000:22ff:fe12:01',
},
{
public_key ='liatbdT62FbPiDPHKBqXVzrEo6hc5oO5tmEKDMhMTlU=',
endpoint ='ffkwsn02.freifunk-koenigswinter.de:30020',
link_address = 'fe80::f000:22ff:fe12:02',
},
{
public_key ='xakSGG39D1v90j3Z9eVWzojh6nDbnsVUc/RByVdcKB0=',
endpoint ='ffkwsn03.freifunk-koenigswinter.de:30020',
link_address = 'fe80::f000:22ff:fe12:07',
},
},
},
```
And you should include the package in the site.mk of course!
### Dependencies
This relies on a broker which accepts post requests like `{'node_name': 'name', 'public_key': 'my_wg_pubkey'}`.
The broker adds the publickey to the WireGuard supernodes so that they accept the WireGuard key which is transmitted during connection.
### How it works
When `checkuplink` gets called (which happens every minute via cronjob), it checks if the gateway connection is still alive by calling `wget` and connecting to `wireguard.peer.peer_[number].link_address`. If this address replies we also start a `batctl ping` to the same address. If both checks succeed the connection just stays alive.
If one of the checks above bails out with an error the reconnect cycle is started. Which means `checkuplink` registers itself with `wireguard.broker` by sending the WireGuard public_key over either http or https (depending on the device support). After the key was sent the script tries to randomely connect to one of the `wireguard.peer`. This script prefers to establish connections over IPv6 and falls back to IPv4 only if there is no IPv6 default route.
### Interesting Links
- [FFAC Broker](https://github.com/ffac/ff-supernode/blob/main/playbooks/roles/ff.wgbroker/templates/broker.py)
- [FFMUC: Half a year with WireGuard](https://www.slideshare.net/AnnikaWickert/ffmuc-half-a-year-with-wireguard)
- [FFMUC: WireGuard Firmware (German)](https://ffmuc.net/freifunkmuc/2020/12/03/wireguard-firmware/)
- [FFMUC: Statistics](https://stats.ffmuc.net)
### Upstream
This package is compatible with the upstream support for wireguard added in Gluon.
In contrast to FFMUC it uses:
- udp6zerocsumtx and udp6zerocsumrx
- 4789
- different domain_seed_bytes calculation
- public_key instead of publickey in site
#!/bin/busybox sh
# shellcheck shell=dash
# fail fast and abort early
set -eu
# set -o pipefail # TODO: pipefail needs more rework in the script
if { set -C; true 2>/dev/null >/var/lock/checkuplink.lock; }; then
trap "rm -f /var/lock/checkuplink.lock" EXIT
else
echo "Lock file exists... exiting"
exit
fi
interface_linklocal() {
# We generate a predictable v6 address
local macaddr oldIFS
# TODO: investigate why this printf is needed here
macaddr="$(printf "%s" "$(uci get network.wg_mesh.private_key | wg pubkey)" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')"
oldIFS="$IFS"
IFS=':'
# shellcheck disable=SC2086 # we need to split macaddr here using IFS
set -- $macaddr
IFS="$oldIFS"
echo "fe80::${1}${2}:${3}ff:fe${4}:${5}${6}"
}
clean_port() {
echo "$1" | sed -r 's/:[0-9]+$|\[|\]//g'
}
check_address_family() {
local peer_endpoint="$1"
local gateway
gateway="$(clean_port "$peer_endpoint")"
# Check if we have a default route for v6 if not fallback to v4
if ip -6 route show table 1 | grep -q 'default via'
then
local ipv6
ipv6="$(gluon-wan nslookup "$gateway" | grep 'Address [0-9]' | grep -E -o '([a-f0-9:]+:+)+[a-f0-9]+')"
echo "[$ipv6]$(echo "$peer_endpoint" | grep -E -oe ":[0-9]+$")"
else
local ipv4
ipv4="$(gluon-wan nslookup "$gateway" | grep 'Address [0-9]' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")"
echo "$ipv4$(echo "$peer_endpoint" | grep -E -oe ":[0-9]+$")"
fi
}
# Do we already have a private-key? If not generate one
if ! uci -q get network.wg_mesh.private_key > /dev/null
then
uci set network.wg_mesh=interface
uci set network.wg_mesh.private_key="$(wg genkey)"
uci commit network
fi
# Is wireguard enabled?
if [ "$(uci get wireguard.mesh_vpn.enabled)" = "true" ] || [ "$(uci get wireguard.mesh_vpn.enabled)" = "1" ]; then
#We assume we are not connected by default
CONNECTED=0
MESH_VPN_IFACE=$(uci get wireguard.mesh_vpn.iface)
# Check connectivity to supernode
if wget "http://[$(wg | grep fe80 | awk '{split($3,A,"/")};{print A[1]}')%$MESH_VPN_IFACE]/" --timeout=5 -O/dev/null -q
then
GWMAC=$(batctl gwl | awk '/[*]/{print $2}')
if batctl ping -c 5 "$GWMAC" > /dev/null 2>&1
then
CONNECTED=1
fi
fi
# If we don't have a connection we try to connect
if [ "$CONNECTED" -ne "1" ]; then
logger -t checkuplink "Reconnecting ..."
NTP_SERVERS=$(uci get system.ntp.server)
# shellcheck disable=SC3060 # busybox sh supports string replacement
NTP_SERVERS="${NTP_SERVERS// / -p }" # each separate NTP server needs to be behind a "-p"
# shellcheck disable=SC2086 # we need to expand the list of NTP_SERVERS here
if ! gluon-wan /usr/sbin/ntpd -n -N -S /usr/sbin/ntpd-hotplug -p ${NTP_SERVERS} -q
then
logger -p err -t checkuplink "Unable to establish NTP connection to ${NTP_SERVERS}."
exit 3
fi
# TODO use upstream config schema: uci show wireguard | grep =peer | sed "s/[^_]*_\([^=]*\).*/\1/"
# Get the number of configured peers and randomly select one
NUMBER_OF_PEERS=$(uci -q show wireguard | grep -E -ce "peer_[0-9]+.endpoint")
set +C
if [ -f "/tmp/connect_peer" ] ; then
PEER="$(( ($(cat /tmp/connect_peer) % NUMBER_OF_PEERS) +1 ))"
else
PEER="$(awk -v min=1 -v max="$NUMBER_OF_PEERS" 'BEGIN{srand(); print int(min+rand()*(max-min+1))}')"
fi
echo "$PEER" > /tmp/connect_peer
logger -t checkuplink "Selected peer $PEER"
endpoint="$(check_address_family "$(uci get wireguard.peer_"$PEER".endpoint)")"
logger -t checkuplink "Connecting to $endpoint"
# Delete Interfaces
{
ip link set nomaster dev mesh-vpn >/dev/null 2>&1
ip link delete dev mesh-vpn >/dev/null 2>&1
} || true
ip link delete dev "${MESH_VPN_IFACE}" >/dev/null 2>&1 || true
PUBLICKEY=$(uci get network.wg_mesh.private_key | wg pubkey)
# Push public key to broker, test for https and use if supported
ret=0
wget -q "https://[::1]" || ret=$?
if [ "$ret" -eq 1 ]; then
PROTO=http
else
PROTO=https
fi
NODENAME=$(uci get system.@system[0].hostname)
BROKER=$(uci get wireguard.mesh_vpn.broker)
gluon-wan wget -q -O- --post-data='{"node_name": "'"$NODENAME"'","public_key": "'"$PUBLICKEY"'"}' $PROTO://"$BROKER"
# Bring up the wireguard interface
ip link add dev "$MESH_VPN_IFACE" type wireguard
wg set "$MESH_VPN_IFACE" fwmark 1
uci get network.wg_mesh.private_key | wg set "$MESH_VPN_IFACE" private-key /proc/self/fd/0
ip link set up dev "$MESH_VPN_IFACE"
LINKLOCAL="$(interface_linklocal)"
# Add link-address and Peer
ip address add "${LINKLOCAL}"/64 dev "$MESH_VPN_IFACE"
if [ "$endpoint" = "" ]; then
endpoint=$(uci get wireguard.peer_"$PEER".endpoint)
fi
gluon-wan wg set "$MESH_VPN_IFACE" peer "$(uci get wireguard.peer_"$PEER".public_key)" persistent-keepalive 25 allowed-ips fe80::1/128 endpoint "$endpoint"
# We need to allow incoming vxlan traffic on mesh iface
sleep 10
ip6tables -I INPUT 1 -i "$MESH_VPN_IFACE" -m udp -p udp --dport 4789 -j ACCEPT
logger -t checkuplink "vxlan link ${LINKLOCAL}"
# Bring up VXLAN
if ! ip link add mesh-vpn type vxlan id "$(lua -e 'print(tonumber(require("gluon.util").domain_seed_bytes("gluon-mesh-vxlan", 3), 16))')" local "${LINKLOCAL}" remote fe80::1 dstport 4789 dev "$MESH_VPN_IFACE" udp6zerocsumtx udp6zerocsumrx
then
logger -p err -t checkuplink "Unable to create mesh-vpn interface"
exit 2
fi
ip link set up dev mesh-vpn
sleep 5
# If we have a BATMAN_V env we need to correct the throughput value now
batctl hardif mesh-vpn throughput_override 1000mbit;
fi
fi
* * * * * sleep $(awk 'BEGIN{srand();print int(rand()*40)}') && /lib/gluon/gluon-mesh-wireguard-vxlan/checkuplink
#!/bin/sh
# This script requires a file as argument in which it will remove all comment lines that start with a hash '#'
sed -i '/^\s*\#[^!].*/d; /^\s*\#$/d' "$1"
#!/usr/bin/lua
local site = require 'gluon.site'
local uci = require("simple-uci").cursor()
local wg_enabled = uci:get_bool('wireguard', 'mesh_vpn', 'enabled') or false
-- Clean up previous configuration
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)
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(),
limit = site.mesh_vpn.wireguard.limit(),
broker = site.mesh_vpn.wireguard.broker(),
enabled = mesh_enabled,
})
for name, peer in pairs(site.mesh_vpn.wireguard.peers()) do
uci:section("wireguard", "peer", "peer_" .. name, {
enabled = true,
endpoint = peer.endpoint,
public_key = peer.public_key,
})
end
uci:save('wireguard')
uci:save('gluon')
local uci = require('simple-uci').cursor()
local site = require 'gluon.site'
local util = require 'gluon.util'
local vpn_core = require 'gluon.mesh-vpn'
local M = {}
function M.public_key()
return util.trim(util.exec('/usr/bin/wg show wg_mesh_vpn public-key'))
end
function M.enable(val)
uci:set('wireguard', 'mesh_vpn', 'enabled', val)
uci:save('wireguard')
end
function M.active()
return site.mesh_vpn.wireguard() ~= nil
end
function M.set_limit(ingress_limit, egress_limit)
uci:delete('simple-tc', 'mesh_vpn')
if ingress_limit ~= nil and egress_limit ~= nil then
uci:section('simple-tc', 'interface', 'mesh_vpn', {
ifname = vpn_core.get_interface(),
enabled = true,
limit_egress = egress_limit,
limit_ingress = ingress_limit,
})
end
uci:save('simple-tc')
end
return M
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment