Freifunk Supernode/Gateway

In this tutorial, I will provide a script to setup a Freifunk Supernode/Gateway for personal usage. We will use Wireguard as VPN and batman-adv with compat 15

# installs latest version
apt install batctl
# batctl still includes old BATMAN IV.. even if taken from backports

# manually build batman-adv
git clone https://github.com/open-mesh-mirror/batman-adv.git
cd batman-adv
apt install linux-libc-dev
make
make install

# load kernel module
modprobe batman-adv
# check if loaded
dmesg | grep batman_adv
# see version
batctl -v
echo batman-adv >> /etc/modules
#echo 1 > /proc/sys/net/ipv4/ip_forward
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p

Für Wireguard muss dem Server pro verbindenden Peer ein Public-Key bekannt gemacht werden, damit sich ein Client verbinden kann. Dazu wurde von Freifunk-KBU ein REST-Dienst geschrieben, welcher ähnlich wie bei mullvad VPN funktioniert. Freifunk-Dresden auch. awlnx von Freifunk-MUC hat mit wgkex einen verteilten Dienst geschrieben, der das selbe Problem löst. Freifunk-Franken nutzt Wireguard, jedoch nicht für die normalen Router-Nodes. Freifunk Regensburg hat den wgkex geforked und ohne MQTT im Einsatz

Sources:

Wireguard konfigurieren

Die Upstream-Gluon-Version ist zu großen Teilen statisch zu konfigurieren. Bisher gibt es keine Broker-URL, die Public-Keys müssen manuell verteilt werden. https://github.com/freifunkMUC/site-ffm/issues/169

/etc/wireguard/wg-ffac_welt.conf

[Interface]
Address = 192.168.17.1/24,fe80::11/64
ListenPort = 51820
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
PreUp = iptables -A POSTROUTING -o ens160 -j MASQUERADE -t nat; ip6tables -t nat -A POSTROUTING -o ens160>
PreDown = iptables -D POSTROUTING -o ens160 -j MASQUERADE -t nat; ip6tables -t nat -D POSTROUTING -o ens1>

[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
AllowedIPs = fe80::1/64

Entsprechend zum Testen auch der client:

[Interface]
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
Address = 192.168.17.4/32, fd42:42:42::4/128
#DNS = 9.9.9.9

[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
Endpoint = example.de:51820
AllowedIPs = 0.0.0.0/0, ::/0

Anschließend kann man vom Client einen ping an 192.168.17.1 durchführen und landet auf dem server. Auch Ping ans Internet sollte klappen, wenn nicht fehlt vielleicht ipv4/ip_forward siehe oben.

Batman und VXLAN konfigurieren:

Die VNI, praktisch das VLAN-Tag von VXLAN berechnet sich aus: domain_seed_bytes("gluon-mesh-vxlan", 3)

# BatmanV - compat 15 - Interface automatisch beim boot starten
auto bat0

# batman interface configuration
iface bat0 inet manual
	# https://dokuwiki.nausch.org/doku.php/centos:ansible:ffmuc-rpb4-ol
	pre-up /usr/sbin/batctl ra BATMAN_V
	# interface anlegen
	pre-up ip link add $IFACE type batadv
	up ip link set up dev $IFACE
	post-down ip link del $IFACE

	# iif rules
	post-up ip -4 rule add iif $IFACE prio 200 table ffac
	pre-down ip -4 rule del iif $IFACE prio 200 table ffac

	post-up ip -6 rule add iif $IFACE prio 200 table ffac
	pre-down ip -6 rule del iif $IFACE prio 200 table ffac
# https://wiki.freifunk-franken.de/w/Freifunk-Gateway_aufsetzen/Batman-adv

auto wg-ffac_welt
iface wg-ffac_welt inet static
	requires ens160
	use wireguard
	address 192.168.17.1/24


auto vx-ffac_welt
iface vx-ffac_welt inet manual
	# 2293484 from lua -e 'print(tonumber(require("gluon.util").domain_seed_bytes("gluon-mesh-vxlan", 3), 16))'
    pre-up ip l a dev $IFACE type vxlan id 2293484 dstport 4789 udp6zerocsumtx udp6zerocsumrx #ohne local address fe80::1
	# udp6zerocsumtx udp6zerocsumrx copied from https://www.open-mesh.org/doc/devtools/Mixing_VM_with_gluon_hardware.html
    pre-up ip l s dev $IFACE mtu 1422
	
	pre-up ip addr add fe80::1/64 dev vx-ffac_welt
	#address fe80::1/64
    post-up batctl -m bat0 if add $IFACE

    pre-down batctl -m bat0 if del $IFACE
    post-down ip l d dev $IFACE

NAT lässt sich aktivieren mit: iptables -t nat -A POSTROUTING -o ens160 -j MASQUERADE

Dadurch soll der Router auch direkt auf Internet zugreifen können.

VXLAN testen

Auf dem Server ist bereits im vxlan-Interface die Adresse fe80::1 konfiguriert, wie es das gluon-package verlangt. Falls nicht: ip addr add fe80::1/64 dev vx-ffac_welt

Der Test-Client muss mit dem Wireguard verbunden sein (überprüfen mit wg auf server und client) und weiterhin folgende Befehle bekommen:

# 2293484 from lua -e 'print(tonumber(require("gluon.util").domain_seed_bytes("gluon-mesh-vxlan", 3), 16))'
#ip link add vxlan1 type vxlan id 2293484 remote 192.168.17.1 dstport 4789 dev wg-ffac
ip -6 link add vxlan1 type vxlan id 2293484 remote fe80::1%wg_mesh dstport 4789
ip link set vxlan1 up
ip addr add fe80::2/64 dev vxlan1

Dabei muss wg_mesh der Name der aktiven Wireguard-VPN Verbindung sein. Anschließend sollte mit ping fe80::1%vxlan1 eine Verbindung zum Server im VXLAN erreicht werden können. (aktuell nicht)

verteiltes Gateway

Anschließend muss der wgkex (verteilt) oder wgskex (single Gateway) installiert werden. Alternativ eine andere Lösung zur manuellen Public-Key Verteilung erfolgen.

Ein neuer Client sollte seinen publickey dann mit http://wg-server:5000/api/v1/wg/key/exchange im Server eintragen.

Anschließend sollte sich der Client mit dem Wireguard-Tunnel (Layer 3) verbinden können. Darin liegt das VXLAN (Layer 2), worin wiederum BATMAN (Layer 2) gesprochen wird.

Ein Gluon-Client sollte anschließend das gluon-mesh-vpn-wireguard paket installieren und sich mit dem entsprechenden Endpunkt verbinden.

Update 08.03

Verbindung klappt, VXLAN-Konfiguration ist erfolgt, Ping geht noch nicht.

Gluon-Client mit entsprechenden Paketen wurde gebaut.

Update 16.03

Installation von BATMAN_V hinzugefügt, Konfiguration bisher noch kaputt

Wireguard einmal kaputt konfiguriert

Vom Server aus klappt: ping fe80::274:dfff:fe40:e8e0%wg-ffac_welt

Vom Client aus klappt: ping fe80::1%wg_mesh

Allerdings kein VXLAN, auch nicht durch manuelles Anlegen der Interfaces.

Update 21.03

Durch händische Konfiguration auf einem nicht-gluon Client, hat es nun geklappt:

Wireguard-Konfiguration mit:

Address = fe80::5/128
AllowedIPs = 192.168.17.1/24, fe80::1/64

Dann

# passende ip addresse anlegen, damit vxlan remote addresse klappt
ip addr add 192.168.17.2 dev wg-ffac
# neues vxlan auf dem client anlegen
ip link add vxlan10 type vxlan id 2293484 remote 192.168.17.1 dstport 4789
# ip addresse hinzufügen
ip addr add fe80::20/64 dev vxlan10
# interface aktivieren
ip link set up vxlan10

Ein ping 192.168.17.1 klappt im wg interface und nun klappt auch ping fe80::1%vxlan10 bzw andersrum ping fe80::20%vx-ffac_welt

Na schön, mit nicht lokalen Addressen kann der remote korrekt konfiguriert werden. Wie kriegt man das nun mit link-local addressen verbastelt?

Es scheint, als würden die anderen immer mit pyroute eine neue route und irgendwie einen FDB Eintrag hinzufügen: https://github.com/freifunkh/wireguard-vxlan-glue/blob/master/netlink.py#L147

Die man-page sagt, das remote-Kommando

specifies the unicast destination IP address to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database

FDB steht also für Forwarding Database und das setzen des remotes wird einfach umgangen indem ein sinnvoller fdb eintrag angelegt wird. Aber wie klappt das manuell?

Update 29.03

https://github.com/freifunk-gluon/community-packages/blob/master/ffmuc-mesh-vpn-wireguard-vxlan/files/lib/gluon/gluon-mesh-wireguard-vxlan/checkuplink#L10

interface_linklocal() {
	# We generate a predictable v6 address
	local macaddr="$(echo $(uci get wireguard.mesh_vpn.privatekey | wg pubkey) |md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')"
	local oldIFS="$IFS"; IFS=':'; set -- $macaddr; IFS="$oldIFS"
	echo "fe80::$1$2:$3ff:fe$4:$5$6"
}

bridge fdb append to 00:00:00:00:00:00 dst $(link_local $1) dev vx-welt und ip ro add $(link_local $1) dev wg-ffac_welt

https://github.com/freifunk-gluon/community-packages/pull/6#issuecomment-681118964

die IP-Adresse ist die vom (über wireguard) verbundenen Gluon-Node Die Antwort ist: RTNETLINK answers: Address family not supported by protocol

Dann muss man überall sicherstellen, dass ip -6 verwendet wird. Dann klappt das auch.

Update 18.06

Eine allgemeine Anleitung auf Basis von Ansible zur Errichtung eines Supernodes habe ich nun hier veröffentlicht:

https://github.com/maurerle/ff-supernode

Dies ist stark inspiriert von https://github.com/freifunkh/ansible und soll den Umstieg für andere Communities erleichtern

Weitere TODOs

  • Wie kann automatische Segmentierung bestehender Knoten funktionieren, um kleinere Mesh-Wolken zu erzeugen?

    • anhand location kann segment gesetzt werden - dadurch wird dann die Freifunk-Domain entschieden
    • neuer wg-autosegmenter schreibt in wg-peers repo rein und schiebt keys zwischen den domains hin und her
    • zugehöriger public Key darf nur in eine Domain rein und wird vom wg-autosegmenter verwaltet
    • Nachteil: Nutzer kann seine Domain nicht selber setzen, sondern nur anhand location und nachbarn hoffen, korrekt gesetzt zu werden
  • Handhabung alter Router (Release eine letzten Gluon-2020.x version zum Upgrade der alten Firmware)

  • automatisierte Verteilung der Wireguard Public-Keys (nutzung eines Git-Repos - ermöglicht automatisierung und manuellen flow)

Quellcode:

Quellcode zum Bauen befindet sich hier: https://github.com/maurerle/site