Offloader auf Basis eines Raspberry PI 4B (WireGuard)
Disclaimer: Die Anleitung ist nur für Leute, die sich bereits mit dem Thema Linux auseinander gesetzt haben oder sich intensiv damit beschäftigen wollen!
Diese Anleitung geht von einem Linux Hostrechner aus - sie funktioniert auf quasi allen Linux basierten Betriebssystemen, mit ein paar Anpassungen.
In den nachfolgenden Beispielen zu den Shell-/Konsolen-Befehlen gelt folgende Formatierungen:
- Ein vorangestelltes Dollarzeichen
$
bedeutet, dass der bzw. die Befehle mit Userrechten des gerade angemeldeten Benutzers ausgeführt werden können. - Ein vorangestelltes Raute-Symbol
#
hingegen bedeutet, dass zum Ausführen des Befehls bzw. der Befehle Root-Rechte benötigt werden, die man z.b. mit Hilfe von$ sudo su -
erlangen kann.
Sollten trotz des eingehenden Studiums dieser Anleitung dennoch Fragen offen bleiben, oder unvorhergesehenen Problemstellungen auftreten, findet man im Chat sicher schnell Hilfe und Unterstützung.
Mit dem Raspberry PI 4 ist es das erste Mal möglich, einen Offloader sinnvoll auf einem PI zu betreiben. Denn in dieser Version bietet der Ethernet Anschluss genug Durchsatz, und die CPU ist leistungsfähig genug um eine ordentliche WireGuard Performance zu bieten. Dies war bei den Vorgänger Modellen so leider nicht der Fall.
Für kabelgebundene Clients und/oder Meshing per Kabel benötigt ihr einen VLAN-fähigen Switch!
Angeboten wird das PI in einer 1GB, 2GB und 4GB RAM Variante. Will man wirklich nur einen reinen Offloader ohne Zusatzfunktionen betreiben, reicht im Grunde die 1GB Version. Allerdings ist mehr RAM immer besser ;) und man weiß ja nicht, was man im Endeffekt noch alles darauf betreiben will.
Raspberry Pi OS
Nachdem es aktuell1) noch kein fertiges Gluon Image für das Raspberry PI 4B gibt, holen wir uns nun das aktuelle Raspberry Pi OS (früher unter dem Namen Raspbian bekannt) auf unseren Rechner. Dies hat mitunter auch noch den Charme, dass wir bei Bedarf alle normalen Anwendungen wie Webserver, Chatserver oder z.B. den Unifi-Controller einfach installieren können.
Eine Anleitung zur manuellen Installation findet man auf der offiziellen Raspbian Seite.
Download
Wir laden uns also das betreffende ZIP-Archiv auf unseren Rechner.
$ wget https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2022-04-07/2022-04-04-raspios-bullseye-arm64-lite.img.xz{,.sha256}
Bevor wir nun das Archiv entpacken überprüfen wir noch die Integrität der heruntergeladenen Datei.
$ sha256sum --check 2022-04-04-raspios-bullseye-arm64-lite.zip.sha256
2022-04-04-raspios-bullseye-arm64-lite.zip: OK
Da unser heruntergeladenes Archiv soweit okay ist, können wir dieses entpacken.
$ unzip 2022-04-04-raspios-bullseye-arm64-lite.zip
Archive: 2022-04-04-raspios-bullseye-arm64-lite.zip inflating: 2022-04-04-raspios-bullseye-arm64-lite.img
Kopieren des Images auf die MicroSD-Karte
Nun können wir das Image auf die MicroSD-Karte, die wir später in den Raspberry 4B stecken, kopieren. Wir werfen also am besten einmal einen Blick in das syslog unseres Arbeitsrechners und erkennen so das Device unserer Speicherkarte.
# tail -f /var/log/messages
bzw.
$ sudo tail -f /var/log/syslog
Sep 5 21:10:57 BOFHs-X230 kernel: [12795.867603] mmc0: new high speed SDHC card at address aaaa Sep 5 21:10:57 BOFHs-X230 kernel: [12795.868313] mmcblk0: mmc0:aaaa SC16G 14.8 GiB Sep 5 21:10:57 BOFHs-X230 kernel: [12795.871017] mmcblk0: p1 p2 Sep 5 21:10:58 BOFHs-X230 kernel: [12796.199093] FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck. Sep 5 21:10:58 BOFHs-X230 systemd[1]: Finished Clean the /media/django/boot mount point. Sep 5 21:10:58 BOFHs-X230 udisksd[976]: Mounted /dev/mmcblk0p1 at /media/django/boot on behalf of uid 1001 Sep 5 21:10:58 BOFHs-X230 kernel: [12796.302402] EXT4-fs (mmcblk0p2): recovery complete Sep 5 21:10:58 BOFHs-X230 kernel: [12796.303545] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) Sep 5 21:10:58 BOFHs-X230 systemd[1]: Finished Clean the /media/django/rootfs mount point. Sep 5 21:10:58 BOFHs-X230 udisksd[976]: Mounted /dev/mmcblk0p2 at /media/django/rootfs on behalf of uid 1001 Sep 5 21:11:09 BOFHs-X230 gnome-terminal-[8119]: g_menu_insert_item: assertion 'G_IS_MENU_ITEM (item)' failed
Aus der zweiten Zeile ergibt sich, dass die MicroSD-Karte über die Gerätedatei /dev/mmcblk0
angesprochen werden kann. Die nachfolgenden Zeilen zeigen an, wie das Linux-System den bestehenden Inhalt der Karte interpretiert - tut aber für unsere Zwecke nichts zur Sache, weil wir die Karte eh gleich überschreiben. Achtung: schließt man die MicroSD-Karte z.B. über einen USB-Adapter an, kann sie auch unter einem anderen Namen erscheinen, z.B. /dev/sde
. Und hier ist Gefahr in Verzug, weil die System-Platte des Host-Rechners auch unter /dev/sd<irgendwas>
erscheint, und es auch erfahrenen Benutzern passiert, die Buchstaben zu verwechseln, und beim nachfolgenden Schreibvorgang sein System zerschießt.
Mit Hilfe der Gerätedatei können wir das heruntergeladene Debian Bullseye Image-Datei auf die MicroSD-Karte kopieren. In der Regel hat der „normale Nutzer“ keine Rechte um diese Gerätedatei anzusprechen, wir müssen also als Benutzer root oder mit den Rechten des Benutzers root den Kopiervorgang aufrufen:
# dd if=~/2022-01-28-raspios-bullseye-arm64-lite.img of=/dev/mmcblk0 bs=4M status=progress conv=fsync
bzw.
$ sudo dd if=/home/django/Freifunk/2022-01-28-raspios-bullseye-arm64-lite.img of=/dev/mmcblk0 bs=4M status=progress conv=fsync
Wenn der Kopiervorgang abgeschlossen ist, Karte entfernen und wieder einstecken. Das System erkennt die beiden Partitions auf der Karte. Je nach Systemeinstellungen mountet sie die Partitions automatisch - in der Regel im Verzeichnis /run/media/
oder auch /media/
. Oder es erscheint in der Systemleiste ein Icon für einen neu erkannten Wechseldatenspeicher, den man dann per Mausklick mounten kann. Wer unsicher ist, kann
# mount
aufrufen, und feststellen, wo die root-Partition und die boot-Partition zu finden ist.
Da wir später weder Tastatur noch Monitor an unseren Raspberry 4B anstecken wollen, diesen demnach im headless-Mode betreiben wollen und werden, legen wir noch eine leere Datei ssh
auf der boot-Partition ab. Damit wird beim Hochfahren der ssh-Server auf dem RPi gestartet, mit dessen Hilfe wir uns über das Netzwerk einloggen können. Zum Anlagen dieser Datei ssh
reicht folgender Aufruf, bei dem wir den Pfad, und insbesondere den Usernamen im Pfad, natürlich unseren Gegebenheiten entsprechend anpassen:
# touch /run/media/django/boot/ssh
bzw.
$ touch /media/django/boot/ssh
Anschließend können wir nach einem Unmounten der Partitions /dev/mmcblk0p*
die Micro-SD-Karte in den Kartenslot des Raspberry 4B stecken und den Kleinstcomputer mit dem Netzwerk sowie dem zugehörigen Netzteil verbinden und starten.
Vorbereitende Konfigurationsschritte
Ändern des Default-Passwortes und kopieren des SSH-Public-Keys auf den Raspberry 4
Der Benutzername lautet pi
und das zugehörige Default-Passwort raspberry
. Das Passwort dieses Nutzers ändern wir nun als erstes ab, da sonst die Gefahr besteht, dass Fremde sich unseres Offloaders bemächtigen!
Wir ändern also das Default-Passwort gleich mal ab und packen auch unseren SSH-Public-key auf den Raspberry 4B. Da wir die IP-Adresse, die unser Raspberry vom DHCP-Server zugewiesen bekommt in unserer SSH-Client-Konfigurationsdatei bereits hinterlegt haben, können wir nun den RaspBerry 4B direkt über den definierten Namen raspberry-ansible
ansprechen.
$ ssh -l pi raspberry-ansible -o IdentitiesOnly=yes "passwd" && \ ssh-copy-id -i ~/.ssh/id_ed25519_ffmuc.pub -o IdentitiesOnly=yes pi@raspberry-ansible
Alternativ dazu müssten wir den Raspberry 4B über die IP-Adresse ansprechen, die dieser zugewiesen bekommt. In dem folgenden Beispiel wäre das die IP-Adresse: 192.168.0.25:
$ ssh -l pi 192.168.0.25 -o IdentitiesOnly=yes "passwd" && \ ssh-copy-id -i ~/.ssh/id_ed25519_ffmuc.pub -o IdentitiesOnly=yes [email protected]
In dem folgenden Konfigurationsbeispiel vergeben wir für den Benutzer pi
das Passwort gECzebzn7GYSLvXueECAxeGm7l7
. Beim Ändern des bestehenden Passwortes müssen wir einmal das Default-Passwort raspberry
eingeben und dann 2x das neue gECzebzn7GYSLvXueECAxeGm7l7
. Beim Kopieren des Public-Keys müssen wir dann einmalig das neue geänderte Passwort gECzebzn7GYSLvXueECAxeGm7l7
verwenden.
The authenticity of host '192.168.0.25 (192.168.0.25)' can't be established. ECDSA key fingerprint is SHA256:vXhdvud24tyTUtOan4XeTZ7GzxZDQn9Rj0mxuhimkH4. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.168.0.25' (ECDSA) to the list of known hosts. [email protected]'s password: Current password: raspberry New password: gECzebzn7GYSLvXueECAxeGm7l7 Retype new password: gECzebzn7GYSLvXueECAxeGm7l7 passwd: password updated successfully Changing password for pi. /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/django/.ssh/id_ed25519_freifunk.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys [email protected]'s password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh -o 'IdentitiesOnly=yes' 'pi@raspberry-ansible'" and check to make sure that only the key(s) you wanted were added.
$ ssh raspberry-ansible
Linux raspberrypi 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/STERNCHEN/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Wi-Fi is currently blocked by rfkill. Use raspi-config to set the country before use. pi@raspberrypi:~ $
Mit Hilfe des Befehls exit
verlassen wir bei Bedarf die gerade laufende SSH-Verbindung mit unserem Raspberry 4. Doch bevor wir dies tun, nehmen wir noch ein paar grundlegende Konfigurationsschritte vor, die nachfolgend beschrieben sind.
Installation von VIM
Für die weiteren Konfigurationsschritte werden Root-Rechte benötigen, schlüpfen wir also als erstes in dessen Rolle:
$ sudo su -
Wi-Fi is currently blocked by rfkill. Use raspi-config to set the country before use. root@raspberrypi:~#
Anschließend installieren wir uns am besten die weiterentwickelte Variante vim des Standard-Editors vi - wir wollen uns ja später die Arbeit nicht unnötig schwer machen.
# apt install vim -y
Änderung des Hostnamens
Unser neuer Offloader braucht einen eigenen Namen, mit dem er sich von anderen eigenen Raspberry P4 unterscheiden lässt. In unserem Konfigurationsbeispiel soll der Name rpb4-wg-ol
lauten. Das Setzen des Nodenamens, mit der unser Offloader dann auch auf der Freifunk-Karte später erscheinen wird, erfolgt im Abschnitt Konfiguration des ext-respondd!
Wir setzen den Hostnamen wie folgt:
# hostnamectl set-hostname rpb4-wg-ol
Damit es beim späteren Wechsel der Userrechte zu keiner Warnmeldung kommt, weil der Hostname nicht aufgelöst werden konnte, korrigieren wir gleich noch die Konfigurationsdatei /etc/hosts
, und ändern auch dort den Standardnamen raspberrypi
auf unseren neuen individuellen Namen rpb4-wg-ol
ab.
# vim /etc/hosts
- /etc/hosts
127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters # Django : 2020-12-16 # default: 127.0.1.1 raspberrypi 127.0.1.1 rpb4-wg-ol
Will man später nachvollziehen, welche Änderungen durch wen und wann gemacht wurden, kann es sehr hilfreich und zweckmäßig sein, entsprechende Änderungen in den Konfigurationsdateien, wie in dem gezeigtem Beispiel nachvollziehbar zu dokumentieren.
Entsperren des WiFi-Unterstützung
Möchte später auch das WLAN des Raspberry verwenden, so ist es zwingend von Nöten, dass WIFI explizit via rfkill freizugeben! Hier loggen wir uns per SSH ein und setzen folgenden Befehl ab:
# rfkill unblock wifi
Erst ein Reboot unseres Raspberry 4 aktiviert das WLAN tatsächlich!
# systemctl reboot
Initialer Update/Upgrade
Doch bevor wir unseren Raspberry 4 neu starten nehmen wir noch einen Update bzw. Upgrade aller installierten Pakete und -quellen vor!
# apt-get update
# apt-get upgrade -y
Nun ist es dann doch an der Zeit, dass wir unseren Kleinstrechner rpb4-wg-ol neu zu starten.
# systemctl reboot
BATMAN
Für das Routing der Layer-2-Verbindungen innerhalb des Freifunknetzes wird als Mesh-Protokoll B.A.T.M.A.N.-Advanced kurz batman-adv
eingesetzt, welches wir uns nun in diesem Abschnitt installieren und konfigurieren wollen.
Am Besten vergewissern wir uns noch vorab, welches die aktuelle BATMAN Version ist. Anfang August 2022 wäre dies die Version 2020.2
Download und entpacken
Nach dem erfolgten Neustart des Rechners melden wir uns wieder mit Hilfe der SSH an unserem Ziel-Host an.
$ ssh -l pi 192.168.0.25
Für die weiteren Konfigurationsschritte werden wie gewohnt Root-Rechte benötigt.
$ sudo su -
Nachdem wir uns eingeloggt haben, wechseln wir in das Zielverzeichnis /usr/src/
, laden dort das aktuelle B.A.T.M.A.N advanced Archiv herunter und entpacken es anschließend an Ort uns Stelle.
# cd /usr/src/
# wget https://downloads.open-mesh.org/batman/releases/batman-adv-2022.2/batman-adv-2022.2.tar.gz{,.sha1}
Bevor wir nun das Archiv entpacken überprüfen wir noch die Integrität der heruntergeladenen Datei.
$ sha1sum --check batman-adv-2022.2.tar.gz.sha1
batman-adv-2022.2.tar.gz.sha1: OK
# tar xzf batman-adv-2022.2.tar.gz
Kernelmodule
Nachdem das Kernelmodul manuell gebaut wird, wollen wir natürlich, dass das auch Bestand hat, wenn ein Kernelupdate eingespielt wird. Dazu brauchen wir nun einige Pakete, die wir erst einmal installieren werden.
# apt update && apt install dkms raspberrypi-kernel-headers
Anschließend müssen wir die make Skripte neu generieren, weil der Raspberry PI Kernel ursprünglich crosscompiliert wurde.
# cd linux-headers-$(uname -r)
# make scripts
Es kann passieren, dass hier nach einiger Zeit mit der nachfolgenden Fehlermeldung abgebrochen wird, das stellt aber kein Problem dar:
HOSTCC scripts/sortextable scripts/sortextable.c:31:10: fatal error: tools/be_byteshift.h: No such file or directory #include <tools/be_byteshift.h> ^~~~~~~~~~~~~~~~~~~~~~ compilation terminated. make[1]: *** [scripts/Makefile.host:107: scripts/sortextable] Error 1 make: *** [Makefile:1123: scripts] Error 2
Da nun alle nötigen vorbereitenden Installations- und Konfigurationsschritte abgearbeitet sind, machen wir uns an das Anlegen der für B.A.T.M.A.N. notwendigen Konfigurationsdatei dkms.conf
.
# cd ../batman-adv-2022.0/
# vim dkms.conf
Der Inhalt der dkms.conf sieht wie folgt aus:
- /usr/src/batman-adv-2022.2/dkms.conf
# Django : 2020-12-15 PACKAGE_NAME=batman-adv PACKAGE_VERSION=2022.2 DEST_MODULE_LOCATION=/extra BUILT_MODULE_NAME=batman-adv BUILT_MODULE_LOCATION=net/batman-adv MAKE="'make'" CLEAN="'make' clean" AUTOINSTALL="yes"
Zum Speichern und Verlassen des Editors vim benutzen wir den Vim-Syntax ESC :x
.
Nun sind wir mit unserer Konfiguration soweit, dass wir die B.A.T.M.A.N-Kernelmodule bauen können.
# dkms add -m batman-adv -v 2022.2
# dkms build -m batman-adv -v 2022.2
# dkms install -m batman-adv -v 2022.2
Als nächstes müssen wir dafür sorgen, dass die beiden Kernelmodule batman-adv und dummy beim Booten des Systems auch geladen werden. Dazu müssen wir die Datei „/etc/modules-load.d/batman-adv.module.conf“ wie folgt anpassen.
# vim /etc/modules-load.d/batman-adv.module.conf
- /etc/modules-load.d/batman-adv.module.conf
# Django : 2020-12-15 # # Load batman-adv module on system boot # batman-adv dummy
Zum Aktivieren kann man nun entweder rebooten oder die Module wie nachfolgend gezeigt manuell laden.
# modprobe dummy
# modprobe batman_adv
Wollen wir überprüfen ob beide Module geladen sind, können wir dies mit den folgenden Befehl(en) abfragen:
# lsmod | grep dummy && lsmod | grep batman_adv
dummy 16384 0 batman_adv 184320 0 bridge 139264 1 batman_adv cfg80211 675840 2 batman_adv,brcmfmac
Installation und Konfiguration von batctl
Um BATMAN verwalten zu können müssen wir nun noch „batctl“ installieren.
# apt-key adv --keyserver hkps://keyserver.ubuntu.com --recv-key 04EE7237B7D453EC
# apt-key adv --keyserver hkps://keyserver.ubuntu.com --recv-key 648ACFD622F3D138
# echo "deb http://deb.debian.org/debian bullseye-backports main contrib non-free" | tee /etc/apt/sources.list.d/bullseye-backports.list
# apt update
# apt-get -t bullseye-backports install batctl
Anschließend überprüfen wir ob alles korrekt geladen wurde.
# batctl ra
Selected routing algorithm (used when next batX interface is created): => BATMAN_IV Available routing algorithms: * BATMAN_IV * BATMAN_V
Nachdem bei Freifunk München BATMAN_V verwendet wird, sehen wir dass aktuell der falsche Routing Algorithmus ausgewählt ist. Das korrigieren einmal sofort manuell.
# batctl ra BATMAN_V
Eine erneute Abfrage zeigt nun auf den korrekten Routing Algorithmus BATMAN_V.
# batctl ra
Selected routing algorithm (used when next batX interface is created): => BATMAN_V Available routing algorithms: * BATMAN_IV * BATMAN_V
Nun kommen wir zur Interface Konfiguration. In diesem Beispiel werden wir den RPi-Offloader im Segment „welt“ ansiedeln, deswegen benennen wir das zugehörige Interface br-welt
auch entsprechend. Hierzu benötigen wir noch die bridge-utils
, die wir uns noch installieren:
# apt install bridge-utils -y
Wir können mit nachfolgendem Befehl überprüfen, ob die Version von batctl
auch zur installierten Version von batman-adv
passt.
# batctl -v
batctl debian-2022.2-1~bpo11+1 [batman-adv: 2022.2]
Da beides in der Version 2022.2 vorliegt, können wir mit der weiteren Installation und Konfiguration wie gewohnt fortfahren.
Interface-Konfiguration
Die Konfiguration selbst nehmen wir über die Datei /etc/network/interfaces
vor, die wir nun entsprechend ergänzen werden.
# vim /etc/network/interfaces
- /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8) # Please note that this file is written to be used with dhcpcd # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' # Include files from /etc/network/interfaces.d: # Django : 2020-12-15 # default: source-directory /etc/network/interfaces.d auto eth0 iface eth0 inet dhcp auto br-welt iface br-welt inet dhcp bridge-ports bat-welt pre-up /usr/sbin/batctl ra BATMAN_V pre-up /sbin/ip link add dummy-welt type dummy pre-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev dummy-welt pre-up /sbin/ip link set dummy-welt up pre-up /usr/sbin/batctl meshif bat-welt if add dummy-welt pre-up /sbin/ip link set bat-welt up pre-up /usr/sbin/batctl meshif bat-welt gw_mode client pre-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev bat-welt post-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev br-welt
In diesem Beispiel setzen wir die MAC Addresse für BATMAN fest auf die MAC von eth0, damit wir später auch Statistiken etc abrufen können. Anschließend starten wir den Raspberry einmal neu!
# systemctl reboot
WIREGUARD
Grundlagen / Hintergründe
Für die Verbindung unseres Offloaders/Nodes zum Freifunk München Netz greifen wir auf den VPN-Tunnel Mechanismus von WireGuard zurück. Hintergründe zum Wechsel von FASTD hin zu WireGuard ist in diesem BlogPost ausführlich beschrieben.
Für die Definition und Einrichtung des WireGuard-VPN-Tunnels werden abhängig vom gewählten Segment folgende Daten und Informationen benötigt:
- Domain : Domain/Segment-Name in dem der Node/Offloader betrieben werden soll.
- Endpoint : Hostname des VPN-Endpunktes / Gateway.
- Port : Port am Gateway
- (remote) publickey : Öffentliche Schlüssel des VPN-Gatway-Endpunktes
- lokale link-local-Adresse : IPv6 Adresse des VPN-Endpunktes am Offloader
- (client) privatekey : Private Schlüssel für den WireGuard-Endpunkt am Offloader
- (client) publickey : Öffentliche Schlüssel für den WireGuard-Endpunkt am Offloader
Bitte informiert euch vorher in welches Segment ihr wollt, dementsprechend müssen die Daten aus nachstehender Tabelle entnommen bzw. lokal generiert werden!
Domain | Tunnel endpoint | Port | link_address am Gateway | publickey Gateway | domain_seed | mesh vpn vxlan id |
---|---|---|---|---|---|---|
ffmuc_muc_cty | gw04.ext.ffmuc.net | 40002 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | a2e8fb0dfb713f6020b893f1c505cee46abb0e63928e8ff1c1fbe3377f56e150 | 3836090 |
ffmuc_muc_cty | gw05.ext.ffmuc.net | 40002 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | a2e8fb0dfb713f6020b893f1c505cee46abb0e63928e8ff1c1fbe3377f56e150 | 3836090 |
ffmuc_muc_cty | gw06.ext.ffmuc.net | 40002 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | a2e8fb0dfb713f6020b893f1c505cee46abb0e63928e8ff1c1fbe3377f56e150 | 3836090 |
ffmuc_muc_cty | gw07.ext.ffmuc.net | 40002 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | a2e8fb0dfb713f6020b893f1c505cee46abb0e63928e8ff1c1fbe3377f56e150 | 3836090 |
ffmuc_muc_nord | gw04.ext.ffmuc.net | 40003 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | ef2c3c3336025a4cb3076a61b112a59a042781c7ce3359d96102d197b99ac89b | 1920014 |
ffmuc_muc_nord | gw05.ext.ffmuc.net | 40003 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | ef2c3c3336025a4cb3076a61b112a59a042781c7ce3359d96102d197b99ac89b | 1920014 |
ffmuc_muc_nord | gw06.ext.ffmuc.net | 40003 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | ef2c3c3336025a4cb3076a61b112a59a042781c7ce3359d96102d197b99ac89b | 1920014 |
ffmuc_muc_nord | gw07.ext.ffmuc.net | 40003 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | ef2c3c3336025a4cb3076a61b112a59a042781c7ce3359d96102d197b99ac89b | 1920014 |
ffmuc_muc_ost | gw04.ext.ffmuc.net | 40004 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 4d57658aaf4428149771a5decfa5d6b7d8b129e3915ebcd5d7329400a6dd48ff | 12097488 |
ffmuc_muc_ost | gw05.ext.ffmuc.net | 40004 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 4d57658aaf4428149771a5decfa5d6b7d8b129e3915ebcd5d7329400a6dd48ff | 12097488 |
ffmuc_muc_ost | gw06.ext.ffmuc.net | 40004 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 4d57658aaf4428149771a5decfa5d6b7d8b129e3915ebcd5d7329400a6dd48ff | 12097488 |
ffmuc_muc_ost | gw07.ext.ffmuc.net | 40004 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 4d57658aaf4428149771a5decfa5d6b7d8b129e3915ebcd5d7329400a6dd48ff | 12097488 |
ffmuc_muc_sued | gw04.ext.ffmuc.net | 40005 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 2461d70aa0453a1fc17131d6eb7ba3a60560d94b376d3039bd6c28a961cfa5e2 | 12815947 |
ffmuc_muc_sued | gw05.ext.ffmuc.net | 40005 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 2461d70aa0453a1fc17131d6eb7ba3a60560d94b376d3039bd6c28a961cfa5e2 | 12815947 |
ffmuc_muc_sued | gw06.ext.ffmuc.net | 40005 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 2461d70aa0453a1fc17131d6eb7ba3a60560d94b376d3039bd6c28a961cfa5e2 | 12815947 |
ffmuc_muc_sued | gw07.ext.ffmuc.net | 40005 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 2461d70aa0453a1fc17131d6eb7ba3a60560d94b376d3039bd6c28a961cfa5e2 | 12815947 |
ffmuc_muc_west | gw04.ext.ffmuc.net | 40006 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 4daea463c2c73009c9dffdd70282ccf5b36407e5179875beae66a5dc823eabe8 | 29149 |
ffmuc_muc_west | gw05.ext.ffmuc.net | 40006 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 4daea463c2c73009c9dffdd70282ccf5b36407e5179875beae66a5dc823eabe8 | 29149 |
ffmuc_muc_west | gw06.ext.ffmuc.net | 40006 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 4daea463c2c73009c9dffdd70282ccf5b36407e5179875beae66a5dc823eabe8 | 29149 |
ffmuc_muc_west | gw07.ext.ffmuc.net | 40006 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 4daea463c2c73009c9dffdd70282ccf5b36407e5179875beae66a5dc823eabe8 | 29149 |
ffmuc_uml_nord | gw04.ext.ffmuc.net | 40007 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | d4fe53ea5eb7d57cecb69b4be43b2eac760e18f10f2f26ff3db801c3b90ea650 | 403289 |
ffmuc_uml_nord | gw05.ext.ffmuc.net | 40007 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | d4fe53ea5eb7d57cecb69b4be43b2eac760e18f10f2f26ff3db801c3b90ea650 | 403289 |
ffmuc_uml_nord | gw06.ext.ffmuc.net | 40007 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | d4fe53ea5eb7d57cecb69b4be43b2eac760e18f10f2f26ff3db801c3b90ea650 | 403289 |
ffmuc_uml_nord | gw07.ext.ffmuc.net | 40007 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | d4fe53ea5eb7d57cecb69b4be43b2eac760e18f10f2f26ff3db801c3b90ea650 | 403289 |
ffmuc_uml_ost | gw04.ext.ffmuc.net | 40008 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 2560ad91705d2e5d259a7abc43a9f5f49631f06b75aae8e8c417c01bab229820 | 12645856 |
ffmuc_uml_ost | gw05.ext.ffmuc.net | 40008 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 2560ad91705d2e5d259a7abc43a9f5f49631f06b75aae8e8c417c01bab229820 | 12645856 |
ffmuc_uml_ost | gw06.ext.ffmuc.net | 40008 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 2560ad91705d2e5d259a7abc43a9f5f49631f06b75aae8e8c417c01bab229820 | 12645856 |
ffmuc_uml_ost | gw07.ext.ffmuc.net | 40008 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 2560ad91705d2e5d259a7abc43a9f5f49631f06b75aae8e8c417c01bab229820 | 12645856 |
ffmuc_uml_sued | gw04.ext.ffmuc.net | 40009 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | f14233863ee4ca3453914505c61f0e0417ed2da0b1695ba13a39bf67e6dabb04 | 12090508 |
ffmuc_uml_sued | gw05.ext.ffmuc.net | 40009 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | f14233863ee4ca3453914505c61f0e0417ed2da0b1695ba13a39bf67e6dabb04 | 12090508 |
ffmuc_uml_sued | gw06.ext.ffmuc.net | 40009 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | f14233863ee4ca3453914505c61f0e0417ed2da0b1695ba13a39bf67e6dabb04 | 12090508 |
ffmuc_uml_sued | gw07.ext.ffmuc.net | 40009 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | f14233863ee4ca3453914505c61f0e0417ed2da0b1695ba13a39bf67e6dabb04 | 12090508 |
ffmuc_uml_west | gw04.ext.ffmuc.net | 40010 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 649b28f2a3c71293d62609e3673d95987d39f4fd19e52f8df4602c80127223b3 | 935867 |
ffmuc_uml_west | gw05.ext.ffmuc.net | 40010 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 649b28f2a3c71293d62609e3673d95987d39f4fd19e52f8df4602c80127223b3 | 935867 |
ffmuc_uml_west | gw06.ext.ffmuc.net | 40010 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 649b28f2a3c71293d62609e3673d95987d39f4fd19e52f8df4602c80127223b3 | 935867 |
ffmuc_uml_west | gw07.ext.ffmuc.net | 40010 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 649b28f2a3c71293d62609e3673d95987d39f4fd19e52f8df4602c80127223b3 | 935867 |
ffmuc_welt | gw04.ext.ffmuc.net | 40011 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26 | 4831583 |
ffmuc_welt | gw05.ext.ffmuc.net | 40011 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26 | 4831583 |
ffmuc_welt | gw06.ext.ffmuc.net | 40011 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26 | 4831583 |
ffmuc_welt | gw07.ext.ffmuc.net | 40011 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26 | 4831583 |
ffmuc_gauting | gw04.ext.ffmuc.net | 40012 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | ae63f3daf9326f3b267b941caf790b2d20eadeacf9ef46d9ca53d7495f559db0 | 4681119 |
ffmuc_gauting | gw05.ext.ffmuc.net | 40012 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | ae63f3daf9326f3b267b941caf790b2d20eadeacf9ef46d9ca53d7495f559db0 | 4681119 |
ffmuc_gauting | gw06.ext.ffmuc.net | 40012 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | ae63f3daf9326f3b267b941caf790b2d20eadeacf9ef46d9ca53d7495f559db0 | 4681119 |
ffmuc_gauting | gw07.ext.ffmuc.net | 40012 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | ae63f3daf9326f3b267b941caf790b2d20eadeacf9ef46d9ca53d7495f559db0 | 4681119 |
ffmuc_freising | gw04.ext.ffmuc.net | 40013 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | e50c53517f25160c134711e4e39a0240d3cf4f4b0adfd950ac232bad2c5c264b | 4669918 |
ffmuc_freising | gw05.ext.ffmuc.net | 40013 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | e50c53517f25160c134711e4e39a0240d3cf4f4b0adfd950ac232bad2c5c264b | 4669918 |
ffmuc_freising | gw06.ext.ffmuc.net | 40013 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | e50c53517f25160c134711e4e39a0240d3cf4f4b0adfd950ac232bad2c5c264b | 4669918 |
ffmuc_freising | gw07.ext.ffmuc.net | 40013 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | e50c53517f25160c134711e4e39a0240d3cf4f4b0adfd950ac232bad2c5c264b | 4669918 |
ffmuc_augsburg | gw04.ext.ffmuc.net | 40014 | fe80::27c:16ff:fec0:6c74 | TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= | a5fcde9c4e52267d204f473d053abb9bbcf49501200f0ddb57041c6624e8c544 | 2962115 |
ffmuc_augsburg | gw05.ext.ffmuc.net | 40014 | fe80::281:8eff:fef0:73aa | igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg= | a5fcde9c4e52267d204f473d053abb9bbcf49501200f0ddb57041c6624e8c544 | 2962115 |
ffmuc_augsburg | gw06.ext.ffmuc.net | 40014 | fe80::2a2:e4ff:fef9:2269 | pkRaUOoLuuHnUt9BEGeKrhF3OMYBPecc0iYkika6uhE= | a5fcde9c4e52267d204f473d053abb9bbcf49501200f0ddb57041c6624e8c544 | 2962115 |
ffmuc_augsburg | gw07.ext.ffmuc.net | 40014 | fe80::23b:d2ff:fe95:967f | PcKkakZcTEx3LKh+G06Opb8/esg08aWK33A5/Ff1YXE= | a5fcde9c4e52267d204f473d053abb9bbcf49501200f0ddb57041c6624e8c544 | 2962115 |
Installation
Das zu WireGuard gehörige Programm wg
mit den entsprechenden Kernelmodulen installieren wir uns nun mit Hilfe von apt
.
# apt install wireguard --assume-yes
Konfiguration
In unserem Konfigurationsbeispiel wollen wir unseren Offloader im Segment ffmuc_welt betreiben und uns mit dem Gateway gw04 von Freifunk München verbinden. Demnach lauten die Daten für den VPN-Tunnelendpunkt:
Qualifier | Value |
---|---|
Domain: | ffmuc_welt |
Hostname/Endpoint: | gw04.ext.ffmuc.net |
Port: | 40011 |
(remote) publickey: | BJHuqV8mXsS9AlAY+x/oi1AsQCm5aMTLOQvLprNZLRo= |
link-local-Adresse: | errechnet sich aus dem nachfolgenden client_public.key |
(client) privatekey: | wird mit Hilfe des binaries wg local generiert und in /etc/wireguard/client_private.key gespeichert. |
(client) publickey: | wird mit Hilfe des binaries wg local generiert und in /etc/wireguard/client_public.key gespeichert. |
Wir erzeugen nun im ersten Schritt das Schlüsselpaar (private-/public-key) für unseren VPN-Client.
# wg genkey | tee /etc/wireguard/client_private.key | wg pubkey | tee /etc/wireguard/client_public.key
Im Konfigurationsverzeichnis von WireGuard finden wir nun beide Schlüssel. Die Dateiberechtigungen passen wir gleich mal noch an, damit nur der User root auf diese zugreifen kann.
# chmod 600 /etc/wireguard/*.key
Die link-local IPv6-Adresse unseres lokalen VPN-Entpunktes ermitteln wir mit Hilfe folgenden Befehls, nachdem wir den public.key zuvor erfolgreich erstellt hatten.
# cat /etc/wireguard/client_public.key | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/fe80::02\1:\2ff:fe\3:\4\5/' > /etc/wireguard/link-local
In unserem Konfigurationsbeispiel ergibt sich also aus dem öffentlichen Schlüssel HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU=
die link-local-Adresse fe80::02c5:ddff:fee7:823b
.
Zusammengefasst haben wir also nunmehr folgende Konfigurationsparameter:
Qualifier | Value |
---|---|
Domain: | ffmuc_welt |
Hostname: | gw04.ext.ffmuc.net |
Port: | 40011 |
(remote) publickey: | BJHuqV8mXsS9AlAY+x/oi1AsQCm5aMTLOQvLprNZLRo= |
lokale link-local-Adresse: | fe80::02c5:ddff:fee7:823b |
(client) privatekey: | WOzTMy6u2Tad4hqBK9jn1KR5aMiu1ZDcD0KLHWlK9nY= |
(client) publickey: | HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU= |
WICHTIG: Der private Schlüssel unseres Clients (privatekey) ist natürlich nicht publik zu machen und ist nur hier im Rahmen dieses How2s abgedruckt, damit die weitere Konfiguration leichter zu verstehen ist. Im Relalife-Betrieb hüten wir diesen Schlüssel natürlich wie immer „wie unseren Augapfel“!
Damit nun das Gateway auch VPN-Verbindungen unseres WireGuard-clients akzeptieren kann benötigt dieses natürlich unseren public-key, den wir nun an das Gateway schicken müssen:
# wget -q -O- --post-data='{"domain": "ffmuc_welt","public_key": "HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU="}' http://broker.ffmuc.net/api/v1/wg/key/exchange
{"Message":"OK"}
Die Bestätigung „Message“:„OK“
zeigt uns, dass der Broker auf der Zielseite, also auf den Gatewasy unseren Pblic-key akzeptiert hat und diesen beim nachfolgenden Tunnelaufbau auch verwenden wird!
Damit nun der Broker vor dem Starten unseres Tunnels auch immer unseren öffentlichen Schlüssel hat, stellen wir nun noch sicher, dass dieser automatisiert vor dem Starten des WireGuard-Daemon einmal zum Broker|Gateway übertragen wird. Hierzu legen wir uns ein systemd-Startscript an.
# vim /etc/systemd/system/broker.service
- /etc/systemd/system/broker.service
# Django : 2020-12-15 [Unit] # see man systemd.unit Description=Inform tunnel about our wireguard-public key Documentation=https://wiki.mailserver.guru/doku.php/centos:ansible:ffmuc-rpb4-ol Before=wg-quick.target [Service] # see man systemd.service, systemd.exec ExecStart=/usr/bin/wget -q -O- --post-data='{"domain": "ffmuc_welt","public_key": "HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU="}' http://broker.ffmuc.net/api/v1/wg/key/exchange StandardOutput=syslog StandardError=syslog [Install] WantedBy=default.target
Damit systemd von unserem neuen Startscript Kenntnis hat, führen wir einen relaod des selbigen durch.
# systemctl daemon-reload
Zum Starten verwenden wir den bekannten Mechanismus von systemd
. Den manuellen Start führen wir mit Hilfe des nachstehenden Befehls aus.
# systemctl start broker.service
Damit der Daemon beim Neustart entsprechend automatisch gestartet wird, setzen wir den Dienst auf enabled
# systemctl enable broker.service
Created symlink /etc/systemd/system/default.target.wants/broker.service → /etc/systemd/system/broker.service.
Was unser Client noch benötigt ist eine rudimentäre Konfigurationsdatei für unseren WireGuard-client, die wir nun als nächstes anlegen müssen.
# vim /etc/wireguard/wg-welt.conf
- /etc/wireguard/wg-welt.conf
# Django : 2020-12-15 [Interface] PrivateKey = WOzTMy6u2Tad4hqBK9jn1KR5aMiu1ZDcD0KLHWlK9nY= Address = fe80::02c5:ddff:fee7:823b [Peer] PublicKey = TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= AllowedIPs = fe80::27c:16ff:fec0:6c74 Endpoint = gw04.ext.ffmuc.net:40011 PersistentKeepalive = 2
Als ersten Test starten wir nun den WireGuard-Tunnel und fahren diesen mit Hilfe des Befehls wg-quick up
hoch.
# wg-quick up wg-welt
[#] ip link add wg-welt type wireguard [#] wg setconf wg-welt /dev/fd/63 [#] ip link set mtu 1412 up dev wg-welt [#] ip -6 route add fe80::27c:16ff:fec0:6c74/128 dev wg-welt
Den Status unseres WireGuard-clients können wir mit Hilfe der Option show beim Aufruf von wg
bzw. nur dur Aufruf von wg
ermitteln
# wg show
oder einfach nur
# wg
zeigen uns den Status des VPN-Tunnels:
interface: wg-welt public key: HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU= private key: (hidden) listening port: 45032 peer: TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g= endpoint: 5.1.66.3:40011 allowed ips: fe80::27c:16ff:fec0:6c74/128 latest handshake: 18 seconds ago transfer: 55.46 MiB received, 212 MiB sent persistent keepalive: every 25 seconds
Da sowohl bei transfer
wie auch bei received
die Werte steigen sobald wie den Status erneut abfragen, können wir im ersten Schritt davon ausgehen, dass der WireGuard-Tunnel steht und auch benutzt werden kann.
Wir sollten auch nun den Tunnelenpunkt am Gateway anpingen können. In unserem Konfiguratiosnbeispiel wäre dies demnach die Ziel-IP-Adresse fe80::27c:16ff:fec0:6c74
auf dem Netzwerk-Device wg-welt
.
# ping6 -c4 fe80::27c:16ff:fec0:6c74%wg-welt
PING fe80::27c:16ff:fec0:6c74%wg-welt(fe80::27c:16ff:fec0:6c74%wg-welt) 56 data bytes 64 bytes from fe80::27c:16ff:fec0:6c74%wg-welt: icmp_seq=1 ttl=64 time=29.2 ms 64 bytes from fe80::27c:16ff:fec0:6c74%wg-welt: icmp_seq=2 ttl=64 time=28.9 ms 64 bytes from fe80::27c:16ff:fec0:6c74%wg-welt: icmp_seq=3 ttl=64 time=28.4 ms 64 bytes from fe80::27c:16ff:fec0:6c74%wg-welt: icmp_seq=4 ttl=64 time=28.10 ms --- fe80::27c:16ff:fec0:6c74%wg-welt ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 7ms rtt min/avg/max/mdev = 28.426/28.884/29.201/0.308 ms
Möchten wir den Tunnel wieder per Hand stoppen, verwenden wir die Option down beim Aufruf des Befehls wg-quick
.
# wg-quick down wg-welt
[#] ip link delete dev wg-welt
Zum Starten und Stoppen verwenden wir aber besser die Mechanismen von systemd
. Den manuellen Start führen wir mit Hilfe des nachstehenden Befehls aus.
# systemctl start wg-quick@wg-welt
Der Stop des WireGuard-Deamon erfolgt entsprechend mit:
# systemctl stop wg-quick@wg-welt
Den Status des WireGuard-Client-daemon fragen wir mit der Option status ab.
# systemctl status wg-quick@wg-welt
● [email protected] - WireGuard via wg-quick(8) for wg/welt Loaded: loaded (/lib/systemd/system/[email protected]; disabled; vendor preset: enabled) Active: active (running) since Wed 2020-12-16 18:20:05 GMT; 10s ago Docs: man:wg-quick(8) man:wg(8) https://www.wireguard.com/ https://www.wireguard.com/quickstart/ https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 Process: 6664 ExecStart=/usr/bin/wg-quick up wg-welt (code=exited, status=0/SUCCESS) Main PID: 6664 (code=exited, status=0/SUCCESS) Dec 16 18:20:05 rpb4-wg-ol systemd[1]: Starting WireGuard via wg-quick(8) for wg/welt... Dec 16 18:20:05 rpb4-wg-ol wg-quick[6664]: [#] ip link add wg-welt type wireguard Dec 16 18:20:05 rpb4-wg-ol wg-quick[6664]: [#] wg setconf wg-welt /dev/fd/63 Dec 16 18:20:05 rpb4-wg-ol wg-quick[6664]: [#] ip link set mtu 1412 up dev wg-welt Dec 16 18:20:05 rpb4-wg-ol wg-quick[6664]: [#] ip -6 route add fe80::27c:16ff:fec0:6c74/128 dev wg-welt Dec 16 18:20:05 rpb4-wg-ol systemd[1]: Started WireGuard via wg-quick(8) for wg/welt.
Damit der Daemon beim Neustart entsprechend automatisch gestartet wird, setzen wir den Dienst auf enabled
# systemctl enable wg-quick@wg-welt
Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] → /lib/systemd/system/[email protected].
WireGuard-Healthcheck
Im Betrieb kann es ab und an passieren, dass der WireGuard-Tunnel zusammenbricht, weil z.B. die Netzwerkverbindung abgerissen ist, oder ein Reboot der Gateways notwendig war. Damit in einem solchen Fall unser Offloader nicht offload geht, müssen wir die Verfügbar- und Nutzbarkeit der Tunnelverbindung in regelmässigen Abständen prüfen und ggf. einschreiten und die Verbindung neu aufbauen.
Da wir das natürlich nicht manuell erledigen wollen und können, legen wir uns ein kleines bash-Script hierzu an.
# vim /usr/local/bin/checkup
- /usr/local/bin/checkup
#!/bin/bash # Django : 2020-12-15 # Check connectivity to supernode HTTP_STATUS_CODE=(`curl --silent --interface wg-welt --get --ipv6 --connect-timeout 5 --write-out '%{http_code}' --output /dev/null 'http://[fe80::27c:16ff:fec0:6c74]:80'`) if [ ${HTTP_STATUS_CODE} != "200" ]; then logger -t checkuplink "curl --silent --interface wg-welt --get --ipv6 --connect-timeout 5 --write-out '%{http_code}' --output /dev/null 'http://[fe80::27c:16ff:fec0:6c74]:80' faild with HTTP-errorcode: ${HTTP_STATUS_CODE}" logger -t checkuplink "... better we restart the wireguard-tunnel!" ip link set nomaster bat-welt dev vxlan-mesh &> /dev/null ip link del dev mesh-vpn &> /dev/null ip link del wg-welt &> /dev/null systemctl stop wg-quick@wg-welt systemctl restart networking logger -t checkuplink "Sending public-key to the broker." /usr/bin/wget -q -O- --post-data='{"domain":"ffmuc_welt","public_key":"HjDRCwE4Q7UPAKXrmM4s6VOgMK+HJZCixWTaVC8KiRU="}' http://broker.ffmuc.net/api/v1/wg/key/exchange logger -t checkuplink "Starting wireguard-daemon." systemctl start wg-quick@wg-welt logger -t checkuplink "Starting vxlan-meshing." vxlan else #logger -t checkuplink "wiregurad-tunnel is up an running : HTTP-statuscode: ${HTTP_STATUS_CODE}" fi
Zum Ausführen statten wir das Script mit den x
-Rechten aus.
# chmod +x /usr/local/bin/checkup
Damit das Script nun minütlich ausgeführt wird, legen wir noch einen hierzu benötigten Eintrag in der /etc/crontab
an.
# vim /etc/crontab
- /etc/crontab
# /etc/crontab: system-wide crontab # Unlike any other crontab you don't have to run the `crontab' # command to install the new version when you edit this file # and files in /etc/cron.d. These files also have username fields, # that none of the other crontabs do. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed 17 * * * * root cd / && run-parts --report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) # # Django : 2020-12-15 # check wireguard-connection * * * * * root /usr/local/bin/checkup 2>&1 /dev/null
Sollte der WireGuard-Tunnel nun zusammenbrechen, aus welchen Gründen das auch immer passieren möge, wird die Verbindung automatisch wieder aufgebaut und im syslog des Raspberry entsprechend dokumentiert.
Dec 16 19:40:09 rpb4-wg-ol checkuplink curl --silent --interface wg-welt --get --ipv6 --connect-timeout 5 --write-out '%{http_code}' --output /dev/null 'http://[fe80::27c:16ff:fec0:6c74]:80' faild with HTTP-errorcode: 500 Dec 16 19:40:10 rpb4-wg-ol checkuplink "... better we restart the wireguard-tunnel!" Dec 16 19:40:12 rpb4-wg-ol checkuplink "Sending public-key to the broker." Dec 16 19:40:16 rpb4-wg-ol checkuplink "Starting wireguard-daemon." Dec 16 19:40:18 rpb4-wg-ol checkuplink "Starting vxlan-meshing."
Mesh per vxlan
Hintergründe
WireGuard selbst transportiert lediglich Layer-3-Verbindungen und keine Layer-2-Verbindungen, welches wir aber für das von uns eingesetzte Meshprotokoll, B.A.T.M.A.N.-Advanced batman-adv, benötigen. Hierzu transportieren wir nun durch den WireGuard-Tunnel ein Virtual eXtensible LAN (VXLAN, siehe RFC 7348) und in diesem VXLAN läuft dann batman-adv.
WICHTIG:
Die hierzu nötige vxlan id darf nicht mit der VX-LAN-ID verwechselt werden, die wir ggf. später zum Meshen hinter unserem Offloader anbieten möchten.
Berechnung der mesh vpn vxlan id
Die mesh vpn vxlan id berechnet sich aus dem domain_seed
(siehe obige Tabelle).
Um die VXLAN ID aus einem domain_seed zu berechnen haben wir ein kleines Python Skript
geschrieben.
- get_mesh_vpn_vxlan_id_from_domain_seed.py
import sys domain_seed = sys.argv[1] def domain_seed_bytes(key, length): import hashlib ret = '' v = '' i = 0 while len(ret) < 2 * length: i = i + 1 hash_this = v + key + domain_seed + str(i) v = hashlib.md5(hash_this.encode('utf-8')).hexdigest() ret = ret + v return ret[: 2 * length] stuff = int(domain_seed_bytes('gluon-mesh-vpn-vxlan', 3), 16) print(stuff)
Im Beispiel Vom Segment ffmuc_welt ergibt bei einem domain-seed von 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26
, die vxlan id von 4831583
:
$ python3 get_vxlan_id_from_domain_seed.py 1f0b31cecdf980317f453b162ac476ee09cf9997b03e684d4f2f484e75d9cd26
4831583
Konfiguration
Zum Aktivieren der Mesh-Verbindung per vxlan legen wir uns nun ein kleines Bash-Script an.
# vim /usr/local/bin/vxlan
- /usr/local/bin/vxlan
#!/bin/bash # Django : 2020-12-15 # Bring up VXLAN ip link add mesh-vpn type vxlan id 4831583 local fe80::02c5:ddff:fee7:823b remote fe80::27c:16ff:fec0:6c74 dstport 8472 dev wg-welt ip link set up dev mesh-vpn # Bind mesh-vpn to BATMAN-Device /usr/sbin/batctl meshif bat-welt if add mesh-vpn # If we have a BATMAN_V env we need to correct the throughput value now /usr/sbin/batctl hardif mesh-vpn throughput_override 10000
Damit das Script später direkt ausgeführt werden kann statten wir es noch mit den x
-Rechten aus.
# chmod +x /usr/local/bin/vxlan
Damit das vxlan-Meshing automatisch beim Starten unseres Offloaders gestartet wird, legen wir uns auch hier ein entsprechendes systemd-Startscript an.
# vim /etc/systemd/system/vxlan.service
- /etc/systemd/system/vxlan.service
# Django : 2020-12-15 [Unit] # see man systemd.unit Description=Bringing up VXLAN Interface Documentation=https://dokuwiki.nausch.org/doku.php/linux:ansible:ffmuc-rpb4-ol After=wg-quick@wg-welt.service [Service] # see man systemd.service, systemd.exec Type=oneshot ExecStart=/usr/local/bin/vxlan StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target
Wie schon zuvor bei unserem Broker-Informations-systemd-Startscript informieren wir hier nun systemd über unsere neue systemd-Startupdatei.
# systemctl daemon-reload
Nun können wir das vxlan-Meshing via systemd starten.
# systemctl start vxlan.service
Für den automatischen Start beim Hochfahren unseres Offloaders aktivieren wir nun noch das entsprechende Script.
# systemctl enable vxlan.service
Created symlink /etc/systemd/system/multi-user.target.wants/vxlan.service → /etc/systemd/system/vxlan.service.
ext-respondd
Dieser Teil ist wichtig, da es sein kann dass man gegen die Nutzungsbedingungen seiner Community verstößt, wenn man sich nicht als Knoten im Netz meldet. Außerdem trägt es generell zur Netzhygiene bei, wenn alle Knoten in den Statistiken auftauchen.
Werteermittlung
Wir ermitteln also am einfachsten die Geo-Koordinaten aus der Freifunk München Karte: https://map.ffmuc.net
Qualifier | Value |
---|---|
Breitengrad: | 48.198104112 |
Längenggrad: | 11.798404455 |
Kontaktadresse: | hier entlang => https://bit.ly/3ajjQC0 |
hostname: | 🧠 wiki-demo 🧠 |
model: | Raspberry Pi 4B |
Installation
Nachdem wir auch auf der Knotenkarte auftauchen wollen, installieren wir auch noch ext-respondd.
# apt install git python3-netifaces -y # git clone https://github.com/freifunkMUC/ext-respondd /opt/ext-respondd/ # cp /opt/ext-respondd/ext-respondd.service.example /etc/systemd/system/ext-respondd.service # systemctl daemon-reload # systemctl enable ext-respondd
Konfiguration
Bevor wir den Daemon starten, müssen wir diesen noch die Konfigurationsdateien von ext-respondd entsprechend anpassen.
WICHTIG:
Darauf achten, dass die Daten inklusive dem Segmentnamen korrekt eingetragen werden. Eine Übersicht der Segmentnamen gibt es hier.
Wir tragen demnach folgende Daten ein:
Qualifier | Value |
---|---|
Breitengrad: | 48.198104112 |
Längenggrad: | 11.798404455 |
Kontaktadresse: | hier entlang => https://bit.ly/3ajjQC0 |
hostname: | 🧠 wiki-demo 🧠 |
model: | Raspberry Pi 4B |
# vim /opt/ext-respondd/alias.json
- /opt/ext-respondd/alias.json
{ "nodeinfo": { "hostname": "🧠 wiki-demo 🧠", "hardware": { "model": "Raspberry Pi 4B" }, "owner": { "contact": "hier entlang => https://bit.ly/3ajjQC0" }, "system": { "site_code": "ffmuc_welt", "role": "client" }, "location": { "latitude": 48.198104112, "longitude": 11.798404455 } }, "firstseen": "2020-12-15T12:15:18" }
# vim /opt/ext-respondd/config.json
- opt/ext-respondd/config.json
{ "batman": "bat-welt", "bridge": "br-welt", "mesh-vpn": [ "fastd-welt" ], "wan": "eth0", "rate_limit": 30, "rate_limit_burst": 10 }
Daemon starten
Nun starten wir unseren Daemon ext-respondd.
# systemctl start ext-respondd.service
Den Status des Daemon fragen wir wie folgt ab.
# systemctl status ext-respondd.service
● ext-respondd.service - ext-respondd (respondd status for servers) Loaded: loaded (/etc/systemd/system/ext-respondd.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-12-16 20:40:11 GMT; 59s ago Main PID: 2184 (python3) Tasks: 1 (limit: 4915) CGroup: /system.slice/ext-respondd.service └─2184 python3 /opt/ext-respondd/ext-respondd.py Dec 16 20:40:11 rpb4-wg-ol systemd[1]: Started ext-respondd (respondd status for servers). Dec 16 20:40:11 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future Dec 16 20:40:31 rpb4-wg-ol ext-respondd.py[2184]: Warning - option -m was deprecated and will be removed in the future
Nach kurzer Zeit taucht unser Node dann auch auf der Karte auf.
Konfigurations-/Netzwerkcheck
Nun wollen wir auch prüfen welche Verbindungen unser Offloader hält.
# ip addr show dev br-welt
6: br-welt: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1280 qdisc noqueue state UP group default qlen 1000 link/ether dc:a6:32:5c:46:07 brd ff:ff:ff:ff:ff:ff inet 10.80.204.2/21 brd 10.80.207.255 scope global dynamic br-welt valid_lft 409sec preferred_lft 409sec inet6 2001:678:e68:109:dea6:32ff:fe5c:4607/64 scope global dynamic mngtmpaddr valid_lft 7118sec preferred_lft 3518sec inet6 fe80::dea6:32ff:fe5c:4607/64 scope link valid_lft forever preferred_lft forever
Wie sehen also, dass unser Node die Adressen 10.80.204.2
sowie 2001:678:e68:109:dea6:32ff:fe5c:4607
hält.
Das Gleiche erreichen wir mit Hilfe dieses Befehls:
# ip -br a | grep br-welt
br-welt UP 10.80.204.2/21 2001:678:e68:109:dea6:32ff:fe5c:4607/64 fe80::dea6:32ff:fe5c:4607/64
Wir sehen somit die Adressen auf unseren Interfaces aus dem gewählten Segment.
Als nächstes prüfen wir, ob die beiden Interfaces dummy-welt
und mesh-vpn
aktiv sind.
# batctl meshif bat-welt if
dummy-welt: active mesh-vpn: active
Den Neighbor unseres Nodes finden wir wie folgt heraus:
# batctl meshif bat-welt n
[B.A.T.M.A.N. adv 2020.4, MainIF/MAC: dummy-welt/dc:a6:32:5c:46:07 (bat-welt/dc:a6:32:5c:46:07 BATMAN_V)] IF Neighbor last-seen 8a:5d:44:50:c3:f8 0.220s ( 10.0) [ mesh-vpn]
Zu guter Letzt sehen wir uns noch die Gateway-Liste an über bzw. mit denen unser Offloader verbunden ist.
# batctl meshif bat-welt gwl
[B.A.T.M.A.N. adv 2020.4, MainIF/MAC: dummy-welt/dc:a6:32:5c:46:07 (bat-welt/dc:a6:32:5c:46:07 BATMAN_V)] Router ( throughput) Next Hop [outgoingIf] Bandwidth * f2:00:25:10:00:00 ( 10.0) 8a:5d:44:50:c3:f8 [ mesh-vpn]: 1000.0/200.0 MBit f2:00:26:10:00:00 ( 10.0) 8a:5d:44:50:c3:f8 [ mesh-vpn]: 1000.0/200.0 MBit
Meshing per Kabel
Möchte man per Kabel meshen, so ist dies auf Grund dessen, dass unser Raspberry nur eine Netzwerkschnittstelle hat, im Grunde nur per VLAN realisierbar.
Dazu ist es erforderlich, dass zuerst ein VLAN Interface in /etc/network/interfaces
angelegt und an das BATMAN Interface anghängt wird.
# vim /etc/network/interfaces
- /etc/network/interfaces
auto eth0.666 iface eth0.666 inet manual post-up /usr/sbin/batctl ra BATMAN_V post-up /usr/sbin/batctl meshif bat-welt if add eth0.666
Bitte beachten:
Das Setup funktioniert nur in Umgebungen ohne VXLAN Meshing. Mit VXLAN Meshing braucht es auch noch ein VXLAN Interface. Details hierzu finden sich im Nachgang!
Mesh per vxlan
Für andere Communities benötigt man die entsprechenden VXLAN IDs zum Meshen - also bei Bedarf bei der lokalen Community nachhaken!
Um meshing per Kabel nutzen zu können, muss bei manchen Communities (wie zum Beispiel bei FFMUC) VXLAN benutzt werden.
Bei uns gibt es momentan folgende VXLAN IDs, diese werden von GLUON dynamisch aus dem domain_seed erzeugt.
Domain | vxlan id |
---|---|
ffmuc_muc_cty | 10758607 |
ffmuc_muc_nord | 15521492 |
ffmuc_muc_ost | 2948862 |
ffmuc_muc_sued | 8599288 |
ffmuc_muc_west | 7318933 |
ffmuc_uml_nord | 5705961 |
ffmuc_uml_ost | 4892713 |
ffmuc_uml_sued | 16544703 |
ffmuc_uml_west | 16677749 |
ffmuc_gauting | 16175732 |
ffmuc_freising | 12937858 |
ffmuc_welt | 16306234 |
ffmuc_augsburg | 10700201 |
Um die VXLAN ID aus einem domain_seed zu berechnen haben wir ein kleines Python Skript geschrieben.
python3 get_vxlan_id_from_domain_seed.py domain_seed
Die Konfiguration in /etc/network/interfaces sieht so aus, um per VLAN666 VXLAN Meshing für das Segment Welt zu machen. Wie ihr seht, wird dafür die ID aus der obigen Tabelle benötigt.
- /etc/network/interfaces
auto eth0.666 iface eth0.666 inet manual pre-up /sbin/ip link add vxlan-mesh type vxlan id 16306234 group ff02::15c dstport 4789 port 32768 61000 no udpcsum udp6zerocsumtx udp6zerocsumrx dev eth0.666 || true up /sbin/ip link set vxlan-mesh up post-up /usr/sbin/batctl ra BATMAN_V post-up /usr/sbin/batctl -m bat-welt if add vxlan-mesh down ip link set vxlan-mesh down post-down ip link del vxlan-mesh || true
Damit das vxlan-mesh Interface auch der bevorzugte Meshingpoint in BATMAN_V wird noch folgendes in die /etc/rc.local
hinzufügen.
# vim /etc/rc.local
- /etc/rc.local
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi # Django : 2020-12-15 /usr/sbin/batctl hardif vxlan-mesh throughput_override 1000000 exit 0
Zum Aktivieren unserer Konfigurationsänderung fahren wir entweder das Netzwerkiinterface hoch oder starten unseren Offloader einfach einmal neu:
# systemctl reboot
Wenn alles geklappt hat und ihr bereits einen Router zum Meshen in diesem VLAN habt, sollte danach folgendes in batctl zu sehen sein.
batctl meshif bat-welt n
[B.A.T.M.A.N. adv 2020.4, MainIF/MAC: dummy-welt/dc:a6:32:5c:46:07 (bat-welt/dc:a6:32:5c:46:07 BATMAN_V)] IF Neighbor last-seen 8e:89:98:45:6c:70 0.380s ( 1.0) [vxlan-mesh] a2:ca:66:65:30:40 0.050s ( 1.0) [vxlan-mesh] 9a:9b:66:30:d9:38 0.110s ( 1.0) [vxlan-mesh] 6a:b4:d0:73:15:47 0.100s ( 10.0) [ mesh-vpn]
Sollte sich kein Client am Mesh VLAN befinden, wird die vxlan-mesh Zeile nicht angezeigt.
Außerdem sollten die Interfaces wie folgt aussehen:
# batctl -m bat-welt if
dummy-welt: active vxlan-mesh: active fastd-welt: active
Leider ist der Link zum Gateway auf der Map nicht zu sehen.
Wifi Clients
Soll der Offloader auch ein WiFI-Clientnetz ausstrahlen, müssen wir hostapd
installieren und konfigurieren. Bei der Vergabe der SSID ist zu beachten:
WICHTIG: Das Abändern der zum Segment passenden SSID ist gemäß der Nutzungsbedingungen nicht gestattet!
- 5. Lokale Zusätze für Freifunk München
Das Betreiben von Routern in Verbindung mit der Freifunk-München Netzwerkinfrastruktur ist nur gestattet, solange die folgenden zwei Bedingungen erfüllt sind:- die SSID des Client-Netzes auf “muenchen.freifunk.net/(Segmentname)” lautet
- die Mesh-BSSID/SSID denen, der in den offiziellen Firmware-Images veröffentlichten, entspricht
Die Liste der SSIDs findet ihr hier:
Aktuell2) gibt es folgende Segmente:
SSID | Segment-Name | IPv4-Prefix | IPv6-Prefix Wien | IPv6-Prefix München |
---|---|---|---|---|
muenchen.freifunk.net/muc_cty | ffmuc_muc_cty | 10.80.128.0/21 | 2001:678:e68:100::/64 | 2001:678:ed0:100::/64 |
muenchen.freifunk.net/muc_nord | ffmuc_muc_nord | 10.80.136.0/21 | 2001:678:e68:101::/64 | 2001:678:ed0:101::/64 |
muenchen.freifunk.net/muc_ost | ffmuc_muc_ost | 10.80.144.0/21 | 2001:678:e68:102::/64 | 2001:678:ed0:102::/64 |
muenchen.freifunk.net/muc_sued | ffmuc_muc_sued | 10.80.152.0/21 | 2001:678:e68:103::/64 | 2001:678:ed0:103::/64 |
muenchen.freifunk.net/muc_west | ffmuc_muc_west | 10.80.160.0/21 | 2001:678:e68:104::/64 | 2001:678:ed0:104::/64 |
muenchen.freifunk.net/uml_nord | ffmuc_uml_nord | 10.80.168.0/21 | 2001:678:e68:105::/64 | 2001:678:ed0:105::/64 |
muenchen.freifunk.net/uml_ost | ffmuc_uml_ost | 10.80.176.0/21 | 2001:678:e68:106::/64 | 2001:678:ed0:106::/64 |
muenchen.freifunk.net/uml_sued | ffmuc_uml_sued | 10.80.184.0/21 | 2001:678:e68:107::/64 | 2001:678:ed0:107::/64 |
muenchen.freifunk.net/uml_west | ffmuc_uml_west | 10.80.192.0/21 | 2001:678:e68:108::/64 | 2001:678:ed0:108::/64 |
muenchen.freifunk.net/welt | ffmuc_welt | 10.80.200.0/21 | 2001:678:e68:109::/64 | 2001:678:ed0:109::/64 |
muenchen.freifunk.net/gauting | ffmuc_gauting | 10.80.208.0/21 | 2001:678:e68:10a::/64 | 2001:678:ed0:10a::/64 |
muenchen.freifunk.net/freising | ffmuc_freising | 10.80.216.0/21 | 2001:678:e68:10b::/64 | 2001:678:ed0:10b::/64 |
muenchen.freifunk.net/augsburg | ffmuc_augsburg | 10.80.224.0/21 | 2001:678:e68:10c::/64 | 2001:678:ed0:10c::/64 |
Installation
# apt install hostapd -y # echo 'DAEMON_OPTS="-d"' >> /etc/default/hostapd
Konfiguration
Nun legen wir uns eine entsprechende Konfigurationsdatei an.
# vim /etc/hostapd/hostapd.conf
- /etc/hostapd/hostapd.conf
# Django : 2020-12-15 ssid=muenchen.freifunk.net/welt country_code=DE interface=wlan0 driver=nl80211 macaddr_acl=0 logger_syslog=0 logger_syslog_level=4 logger_stdout=-1 logger_stdout_level=0 hw_mode=a wmm_enabled=1 # N ieee80211n=1 require_ht=1 ht_capab=[MAX-AMSDU-3839][HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40] # AC ieee80211ac=1 require_vht=1 ieee80211d=0 ieee80211h=0 vht_capab=[MAX-AMSDU-3839][SHORT-GI-80] vht_oper_chwidth=1 channel=36 vht_oper_centr_freq_seg0_idx=42
Anschließend aktivieren und starten wir den hostapd
-Daemon.
# systemctl unmask hostapd # systemctl enable hostapd # systemctl start hostapd
Das Netzwerkinterface wlan0
müssen wir nun noch in die Bridge packen. Dazu passen wir die /etc/rc.local
an.
# vim /etc/rc.local
- /etc/rc.local
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi # Django : 2020-12-15 sleep 10; /sbin/brctl addif br-welt wlan0 exit 0
Am Besten nochmal rebooten um sicher zugehen, dass alles passt, danach einfach mit dem ClientWifi verbinden.
# systemctl reboot
LAN Clients
Will man LAN Clients versorgen, so erstellt man am einfachsten ein VLAN getaggtes Clientnetz. Dazu erstellt man in der Konfigurationsdatei /etc/network/interfaces
die zugehörige Konfiguration. Im folgenden Beispiel nutzen wir die VLAN-ID 333
und definieren zunächst einmal das VLAn-Interface und fügen es anschließend in der vorhandenen Bridge hinzu.
# vim /etc/network/interfaces
- /etc/network/interfaces
auto eth0.333 iface eth0.333 inet manual auto br-welt iface br-welt inet dhcp bridge-ports bat-welt eth0.333
Geschwindigkeiten
Nun zur wichtigsten Frage, welche Performance kann man erwarten.
Hier ein paar Speedtest Ergebnisse:
$ wget -O /dev/null https://speed.hetzner.de/10GB.bin --report-speed=bits
--2019-07-01 09:12:45-- https://speed.hetzner.de/10GB.bin Resolving speed.hetzner.de (speed.hetzner.de)... 88.198.248.254 Connecting to speed.hetzner.de (speed.hetzner.de)|88.198.248.254|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 10485760000 (9.8G) [application/octet-stream] Saving to: ‘/dev/null’ /dev/null 2%[===> ] 288.96M 115Mb/s eta 14m 34s
Uplink per LTE via iOS Gerät
Nebenbei gibt es noch die Möglichkeit, Tethering z.B. mit iOS Geräten zu machen. Dazu muss usbmuxd installiert werden. Und in der /etc/network/interfaces
ein Interface angelegt werden.
# apt install usbmuxd libimobiledevice6 -y # vim /etc/network/interfaces
- /etc/network/interfaces
... allow-hotplug eth1 iface eth1 inet dhcp ...
Am Besten rebootet man den Raspberry Offloader einmal. Danach steckt ihr euer iOS Gerät per USB an während ihr im Hotspot Menü seid und werdet gefragt, ob das PI Zugriff bekommen kann. Das beantwortet ihr mit „Ja“.
Euer PI bezieht sich nun eine IP per DHCP vom iOS Gerät und kann darüber Verbindungen zu den Freifunk Gateways aufbauen.
Und so sieht ein Mobile PI mit iPad als Uplink aus:
OLED Display
Im nachfolgenden Beispiel verwenden wir ein OLED Display von AZDelivery mit 128×64 Pixeln. Das schöne an dem Display ist, es funktioniert auch mit 5V und ist damit noch einfacher anzuschließen.
Anschluss/Verkabelung
Angeschlossen wird das Ganze wie folgt:
OLED Pin | GPIO Pin | Notes |
---|---|---|
Vcc | 4 | 5V |
Gnd | 6 | Ground |
SCL | 5 | I2C SCL |
SDA | 3 | I2C SCA |
I2C-Bus aktivieren
Als nächstes aktivieren wir die I2C Schnittstelle und installieren die notwendige Software.
# echo i2c-bcm2708 >> /etc/modules # echo i2c-dev >> /etc/modules
# apt install python3-dev python3-smbus i2c-tools python3-pil python3-pip python3-setuptools python3-rpi.gpio -y
Bevor wir nun einen Reboot durchführen kontrollieren wir noch, ob in der /boot/config.txt das I2C-Interface auch gestartet wird.
root@raspberrypi:~# vim /boot/config.txt
... # Uncomment some or all of these to enable the optional hardware interfaces # Django : 2020-12-15 - für OLED Display Support aktiviert # default: # dtparam=i2c_arm=on dtparam=i2c_arm=on ...
Nun am Besten einmal rebooten.
# systemctl reboot
Funktionstest
Danach überprüfen wir ob das Display erkannt wird.
# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Wie man sieht meldet sich das Display unter der Adresse 3c.
Installation der Software-Bibliotheken
Jetzt installieren wir die notwendige Python Bibliotheken um das Display ansteuern zu können.
# apt install git fonts-freefont-ttf -y # cd /usr/local/src/ # git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git # cd Adafruit_Python_SSD1306 # python3 setup.py install
Anschließend können wir mit ein paar Beispielen probieren ob das Display korrekt funktioniert.
# cd examples # python3 /usr/local/src/Adafruit_Python_SSD1306/examples/stats.py
Auf dem Display werden ein paar Systemdaten angezeigt:
Script installieren und anpassen
Nachdem alles alles soweit funktioniert, können wir als nächstes das Bandbreiten Skript installieren, welches auch gleichzeitig die verbundenen BATMAN Clients anzeigt.
Anschließend das Python Skript, welches das Display steuert installieren und anpassen.
# cd /usr/local/src # git clone https://github.com/awlx/raspberry-oled-bandwidth # cd raspberry-oled-bandwidth
Nun passen wir in dem Script folgende Variabelen unseren Gegebenheiten an:
wifi
: Die definierte Schnittstelle unseres WiFi-Devicesvpn
: VPN Definitionenbatman
: BATMAN Definitionenprimary_mac
: MAC des Ethernet-Ports unseres Raspberry 4# ip addr show eth0 | grep link/ether
# vim /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
- /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
# # Inspired by https://github.com/DarrenBeck/rpi-oled-bandwidth and https://photochirp.com/r-pi/use-raspberry-pi-oled-bandwidth-monitor/ # # Maintained by awlnx - [email protected] # import subprocess import time import re import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 from PIL import Image from PIL import ImageDraw from PIL import ImageFont import math # Adjust to your needs wifi = 'wlan0' vpn = 'fastd-welt' batman = 'bat-welt' # Django : 2020-12-15 # default: primary_mac = 'dc:a6:32:00:6b:59' primary_mac = 'dc:a6:32:01:7f:f0' # We assume 100mbit/s max bandwidth maxRateIn = 10000000 maxRateOut = 10000000 PImaxRateIn = 10000000 PImaxRateOut = 10000000 ### DO NOT EDIT BELOW THIS POINT ### # Raspberry Pi pin configuration: # Django : 2020-15-12 # default: RST = 24 RST = 'P9_15' # 128x64 display with hardware I2C: disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) # Initialize library. disp.begin() # Clear display. disp.clear() disp.display() # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. width = disp.width height = disp.height image = Image.new('1', (width, height)) # Get drawing object to draw on image. draw = ImageDraw.Draw(image) font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12) fontsmall = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 10) fontverysmall = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 8) fontmedium = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12) #Display Image disp.image(image) disp.display() #Functions def get_network_bytes(interface): for line in open('/proc/net/dev', 'r'): if interface in line: data = line.split('%s:' % interface)[1].split() rx_bytes, tx_bytes = (data[0], data[8]) return (int(rx_bytes), int(tx_bytes)) def drawBar (x, barHeight): # parameters are x, y, end x, end y # draw.rectangle ((x, height - barHeight, x + 10, height -1), outline=255, fill=255) draw.rectangle ((x, 32 - barHeight, x + 8, height - 32), outline=255, fill=255) def drawBarLOW (x, barLOWHeight): # parameters are x, y, end x, end y draw.rectangle ((x, 32 + barLOWHeight, x + 8, height - 32), outline=255, fill=255) def textRate(rate): # rate -> raw bitrate # Returns: SI formatted bitrate if rate == 0: return "0B" rate = rate * 8 size_name = ( "b/s", "kb/s", "mb/s", "gb/s", "tb/s", "pb/s", "eb/s") i = int(math.floor(math.log(rate , 1024))) p = math.pow(1024, i) s = round(rate / p, 1) return "%s %s" % (s, size_name[i]) lastInBytes = get_network_bytes(vpn)[0]; lastOutBytes = get_network_bytes(vpn)[1]; lastPIInBytes = get_network_bytes(wifi)[0]; lastPIOutBytes = get_network_bytes(wifi)[1]; lastTime = time.time() #timed array vars timerTime = time.time() highestSpeedIn = 0 highestSpeedOut = 0 PIhighestSpeedIn = 0 PIhighestSpeedOut = 0 speedArrayIn = [] speedArrayOut = [] PIspeedArrayIn = [] PIspeedArrayOut = [] inMax = 0 outMax = 0 PIinMax = 0 PIoutMax = 0 while (1): time.sleep(2) draw.rectangle((0, 0, width, height), outline=0, fill=0) now = time.time() elapsed = now - lastTime lastTime = now #calculate rates in and out inBytes = get_network_bytes(vpn)[0] currInBytes = (inBytes - lastInBytes) / elapsed lastInBytes = inBytes outBytes = get_network_bytes(vpn)[1] currOutBytes = (outBytes - lastOutBytes) / elapsed lastOutBytes = outBytes PIinBytes = get_network_bytes(wifi)[0] currPIInBytes = (PIinBytes - lastPIInBytes) / elapsed lastPIInBytes = PIinBytes PIoutBytes = get_network_bytes(wifi)[1] currPIOutBytes = (PIoutBytes - lastPIOutBytes) / elapsed lastPIOutBytes = PIoutBytes #max rate last 24 hours calculations if currInBytes > highestSpeedIn: highestSpeedIn = currInBytes if currOutBytes > highestSpeedOut: highestSpeedOut = currOutBytes if currPIInBytes > PIhighestSpeedIn: PIhighestSpeedIn = currPIInBytes if currPIOutBytes > PIhighestSpeedOut: PIhighestSpeedOut = currPIOutBytes if now > timerTime + 3600: print('----------------------------------------------------------------- time expired') timerTime = now speedArrayIn.append (highestSpeedIn) if len (speedArrayIn) > 23: del speedArrayIn[0] inMax = max(speedArrayIn) speedArrayOut.append (highestSpeedOut) if len (speedArrayOut) > 23: del speedArrayOut[0] outMax = max(speedArrayOut) highestSpeedIn = 0 highestSpeedOut = 0 PIspeedArrayIn.append (PIhighestSpeedIn) if len (PIspeedArrayIn) > 23: del PIspeedArrayIn[0] PIinMax = max(PIspeedArrayIn) PIspeedArrayOut.append (PIhighestSpeedOut) if len (PIspeedArrayOut) > 23: del PIspeedArrayOut[0] PIoutMax = max(PIspeedArrayOut) PIhighestSpeedIn = 0 PIhighestSpeedOut = 0 #adjust these in each loop in case we find a faster speed inMax = max(inMax, highestSpeedIn) outMax = max(outMax, highestSpeedOut) PIinMax = max(PIinMax, PIhighestSpeedIn) PIoutMax = max(PIoutMax, PIhighestSpeedOut) #draw graph inHeight = 0.0 outHeight = 0.0 PIinHeight = 0.0 PIoutHeight = 0.0 if currInBytes > 0: inHeight = float(currInBytes / maxRateIn) * 32 if currOutBytes > 0: outHeight = float(currOutBytes / maxRateOut) * 32 if currPIInBytes > 0: PIinHeight = float(currPIInBytes / PImaxRateIn) * 32 if currPIOutBytes > 0: PIoutHeight = float(currPIOutBytes / PImaxRateOut) * 32 drawBar (0, inHeight) drawBar (10, PIinHeight) drawBarLOW (0, outHeight) drawBarLOW (10, PIoutHeight) #write rates draw.text((26,38), textRate(currInBytes), font=font, fill=255) draw.text((26,50), textRate(currOutBytes), font=font, fill=255) draw.text((81,38), textRate(currPIInBytes), font=font, fill=255) draw.text((81,50), textRate(currPIOutBytes), font=font, fill=255) # Batman Clients clients = subprocess.check_output("batctl -m " + batman + " tl | egrep -v '(MainIF|" + primary_mac + ")' | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | wc -l", shell=True).split().pop() draw.text((0,48), "Clients", font=fontverysmall, fill=255) draw.text((10,55), clients.decode("utf-8"), font=fontverysmall, fill=255) #max rates draw.text((36,0), "VPN", font=fontsmall, fill=255) draw.text((26,10), textRate(inMax), font=fontsmall, fill=255) draw.text((26,20), textRate(outMax), font=fontsmall, fill=255) draw.text((90,0), "Wifi", font=fontsmall, fill=255) draw.text((81,10), textRate(PIinMax), font=fontsmall, fill=255) draw.text((81,20), textRate(PIoutMax), font=fontsmall, fill=255) disp.image(image) disp.display()
Nun können das Script erst einmal manuell anstarten und prüfen ob die gewünschten Informationen richtig angezeigt werden.
# /usr/bin/python3 /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
Um nun nicht jedes mal beim Starten des Offloaders/Gateways manuell starten müssen, legen wir uns noch ein systemd-Script an.
# vim /etc/systemd/system/oled-bandwidth.service
- /etc/systemd/system/oled-bandwidth.service
# Django : 2020-12-15 [Unit] After=network.target [Service] ExecStart=/usr/bin/python3 /usr/local/src/raspberry-oled-bandwidth/bandwidth.py [Install] WantedBy=default.target
Anschließend informieren wir unser System über unser definiertes Daemon-Startscript und aktivieren dies auch gleich noch.
# systemctl daemon-reload # systemctl enable oled-bandwidth.service
Zu guter Letzt rebooten wir nun unseren Rechner.
# systemctl reboot