Babel
Funktion
Babel wird als Layer 3 Routingprotokoll in der Freifunk Franken Backbone verwendet. So werden alle Gateways über das Protokoll direkt oder indirekt miteinander verbunden. Babel tauscht gegenseitig die Routen der Gateways aus, so das jedes Gateway weiß über welchen Weg es eine andere Hood erreichen kann.
Vorsicht
ACHTUNG:
IP Adressen dürfen nur announced werden, wenn sie auch erreicht werden können. Wer das Subnetz für Hood A announced muss Hood A auch erreichen können.
Installation
Babel kann direkt aus der Distribution installiert werden.
apt-get install babeld
Debian liefert eine recht alte Version mit. Es ergibt Sinn Babel per apt zu installieren, es dann zu deinstallieren und danach und aus dem Git selbst zu bauen (Version >=1.8.2).
https://github.com/jech/babeld
Änderungen ab Babel 1.8.0
- Die Option 'wired true' gibt es nicht mehr, dafür gibt es jetzt Interface-Typen. Am sinnvollsten für GRE-Tunnel ist wohl 'type tunnel'
- Die neueste Version von BabelWeb (0.4.0) ist nicht mit Babel 1.8.0 kompatibel. Daher muss BabelWeb aus dem develop Branch installiert werden.
Beispielkonfiguration
Diese Beispielkonfiguration kann so übernommen werden.
/etc/babeld.conf
# For more information about this configuration file, refer to # babeld(8) # Überschneidung der Tabellen für Source-Specific IPv4 Routing und der fff-Tabelle verhindern first-table-number 100 #Defaultwerte für die Schnittstellen setzen: default type tunnel max-rtt-penalty 128 #Falls einzelne Schnittstellen abweichend konfiguriert werden müssen: #interface IF2 type wired rxcost 1234 #... einfach weiterführen für mehr Interfaces. export-table 10 import-table 10 # redistribute rules ## Filter für lokalen Routen, die im Babel announced werden. redistribute local ip 10.50.0.0/16 redistribute local ip 10.83.0.0/16 redistribute local ip fd43:5602:29bd::/48 redistribute local deny redistribute ip 10.50.0.0/16 redistribute ip 10.83.0.0/16 redistribute ip fd43:5602:29bd::/48 local-port 33123 #local-port-readwrite 34567 #funktioniert anscheinend nicht!
Man kann alle Peering-Interfaces mit default abfangen (wie oben geschehen) oder für jedes Peering-Interface eine eigene Zeile verwenden.
Die Interfaces, die babel verwenden soll müssen auch in der /etc/default/babeld eingetragen werden - durch Leerschläge getrennt.
/etc/default/babeld
... # List of interfaces on which the protocol should operate INTERFACES="GRE_Beispielinterface1 GRE_Beispielinterface2 WG_Beispielinterface1" ...
Routen die man manuell in die fff Table einträgt und redistributen (weiterverteilen) will, müssen als proto static eingetragen haben. Dies gilt z.b. für die Batman Routen oder auch für die default route (z.b. im VPN Up Script wenn man dies verwendet). Beispiel:
... post-up ip route replace 10.X.X.X/XX dev $IFACE proto static table fff ...
IP Adressen für Peering
IPv4
Es sollte für jeden Server die selbe Adresse verwendet werden auf jedem Interface. Sinnvollerweise aus dem 10.83.252.X Netz: https://wiki.freifunk-franken.de/w/Portal:Netz#10.83.252.0.2F22_.28Master_IPs.29
Dabei ist es am sinnvollsten, die Adresse als /32 an das Interface zu hängen und Babel die Routen übernehmen zu lassen. Hierbei ist es dann auch egal, aus welchem der beiden Prefixe die Adresse stammt (10.83.x.y bzw. 10.50.x.y). Außerdem ist es bei dieser Konfiguration ebenfalls nicht nötig, die Adresse des Partners als Pointopoint anzuhängen.
ACHTUNG: Es ist dann ebenfalls (erstmal) nicht möglich, den Partner direkt zu pingen, da bei dieser Konfiguration keine passende Route in der main-Tabelle existiert!
IPv6
Für IPv6 gilt in etwas das gleiche. Für das Routing ist eine Link Local Adresse nötig. Bei Ethernet und Layer2 Tunneln wird diese automatisch aus der Mac Adresse gebildet. Bei Layer3 Tunneln muss diese ggf. manuell generiert und als /64 an das Interface gehangen werden.
Damit ein Router sinnvoll auf ICMPv6 antworten kann, ist außerdem eine Adresse aus dem fc00::/7 oder eine öffentliche IPv6 nötig. Dafür kann beispielsweise eine IP aus diesem Netz verwendet werden.
Sollte das Netz nicht alleine für diese Verbindung existieren, bietet es sich auch hier an, die Adresse einfach als /128 an das Interface zu hängen.
GRE
Da GRE ein sehr schnelles Tunnelprotokoll ist und wenig Overhead erzeugt macht es Sinn Gateways (sofern beide Seiten eine feste IP haben und nicht hinter NAT stecken) per GRE Tunnel zu verbinden und darüber Babel laufen zu lassen. Alternativ kann z.b. wireguard verwendet werden wenn eine Seite hinter einem NAT steckt und/oder keine feste IP hat (bei dezentralen Gateways oft der Fall). Theoretisch kann man natürlich auch OpenVPN oder fastd oder einen ganz anderen Layer 3 Tunnel verwenden, ob dies Sinn macht muss jeder für sich entscheiden.
Interface anlegen
Um die einzelnen Hoods miteinander zu verbinden, werden die jeweiligen Gateways über GRE-Tunnel miteinander verbunden. Es reicht dabei nicht, den GRE Tunnel nur auf einem Gateway einzurichten, vielmehr müssen beide zu verbindende Gateways konfiguriert werden. Hierfür muss man mit dem Admin des jeweiligen Tunnelpartners in Kontakt treten => Portal:Layer3Peering.
Da Babel über IPv6-Multicasts kommuniziert, müssen den GRE-Tunnel noch link-local Adressen gegeben werden, da GRE-Tunnel auf Layer3 arbeiten und somit keine MAC-Adresse haben -> link-local kann nicht aus MAC automatisch generiert werden. Am besten generiert man sich die link-local zufällig.
Siehe: http://wiki.hwmn.org/w/GRE_Tunnel#Babel_support
Die Schnittstellenkonfiguration sollte dann etwa so aussehen:
auto DEVICENAME iface DEVICENAME inet static address 10.83.252.x/32 #IPv4 GRE #pre-up ip -4 tunnel add $IFACE mode gre local EIGENEPUBLICIP remote REMOTEPUBLICIP ttl 255 #IPv6 GRE pre-up ip -6 tunnel add $IFACE mode ip6gre local EIGENEPUBLICIP remote REMOTEPUBLICIP ttl 255 up ip link set dev $IFACE multicast on post-up ip rule add iif $IFACE table fff post-down ip rule del iif $IFACE table fff post-down ip tunnel del $IFACE iface DEVICENAME inet6 static address fe80::IRGENDWAS/64 post-up ip -6 rule add iif $IFACE table fff post-down ip -6 rule del iif $IFACE table fff
Der Tunnel kann über den Aufruf von
ifup <tunnel>
...aufgebaut werden, wobei <tunnel> der Name des GRE-Interfaces ist (im Beispiel ro1)
Nach Aufruf von ip link bzw. ip addr..
ip link
sollten wir einen Eintrag für den Tunnel vorfinden:
. . yy: DEVICENAME@NONE: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1448 qdisc noqueue state UNKNOWN group default qlen 1 link/gre6 EIGENEPUBLICIP peer REMOTEPUBLICIP inet 10.83.252.x/32 brd 10.83.252.x scope link DEVICENAME valid_lft forever preferred_lft forever inet6 fe80::IRGENDWAS/64 scope link valid_lft forever preferred_lft forever . .
Wireguard
Alternativ zum oben beschriebenen GRE Protokoll kann ein Babel Tunnel auch mit dem Wireguard Protokoll aufgebaut werden. Insbesondere ist dies erforderlich, wenn eine Seite hinter einem NAT steckt und/oder keine feste IP hat (bei dezentralen Gateways oft der Fall).
Installation
Wireguard ist eine recht junge Software und deshalb noch nicht in Debian 9 enthalten. In die Apt Paketverwaltung muss der "unstable" Zweig eingebunden werden. Dies erfolgt nachrangig, damit bei "apt-get upgrade" keine Pakete aus dem unstable Zweig installiert werden, die schon im Hauptzweig existieren.
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' > /etc/apt/preferences.d/limit-unstable
apt-get update
apt-get install wireguard linux-headers-amd64
Interface anlegen
Die Schnittstellenkonfiguration sollte weitgehend genauso aussehen, wie bei GRE beschrieben. Auch die beiden fürs Gateway reservierten IP-Adressen (IPv4 und IPv6) sowie die willkürlich gewählte Link-Local-Adresse (fe80::...) können für GRE und Wireguard gemeinsam verwendet werden.
vi /etc/network/interfaces
auto DEVICENAME iface DEVICENAME inet static address 10.83.252.x/32#IPv4 GRE#pre-up ip -4 tunnel add $IFACE mode gre local EIGENEPUBLICIP remote REMOTEPUBLICIP ttl 255#IPv6 GREpre-up ip -6 tunnel add $IFACE mode ip6gre local EIGENEPUBLICIP remote REMOTEPUBLICIP ttl 255pre-up ip link add $IFACE type wireguard pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf ...post-down ip tunnel del $IFACEpost-down ip link del $IFACE ...
Hierbei wird angenommen, dass die Wireguard-Konfigurationsdateien unter den Dateinamen <DEVICENAME>.conf abgespeichert werden:
vi /etc/wireguard/<DEVICENAME>.conf
# /etc/wireguard/wg-test.conf [Interface] PrivateKey = UBnpiQhEz2S192d8nmFmr2rm3UU+NKpKiBy28fyVa3s= ListenPort = 51820 [Peer] PublicKey = ZAleBcuJ4O9m2hfmz5bnqM0POCAIHQSsnWVBzreJaWw= AllowedIPs = 0.0.0.0/0, ::/0
Dabei ist "PrivateKey" der eigene private Schlüssel, "PublicKey" der öffentliche Schlüssel der Gegenstelle. "ListenPort" ist der Port, auf dem die Pakete der Gegenstelle empfangen werden. "AllowedIPs" sind alle IPs IPv4 und IPv6.
Die Schlüssel können mit folgender Aufrufkette in zwei Dateien "wg-private.key" und "wg-public.key" im aktuellen Verzeichnis erzeugt werden. Diese Schlüssel sollten außerhalb des Servers gesichert werden! Danach können die beiden Dateien gelöscht werden.
wg genkey | tee wg-private.key | wg pubkey > wg-public.key
Weil in der Konfigurationsdatei der geheime private Schlüssel im Klartext steht, empfiehlt es sich anderen Nutzern außer "root" das Lesen zu verbieten.
chmod go-r /etc/wireguard/<DEVICENAME>.conf
Abschließend müssen auch Wireguard Interfaces genauso wie GRE Interfaces in die Datei "/etc/default/babeld" eingefügt werden.
Tests
Nach Aufruf von "ifconfig" sollten wir einen Eintrag für den Tunnel (in diesem Beispiel wg-test) vorfinden.
Der Aufruf "wg show" gibt etwas aus, mindestens den Namen der konfigurierten Interfaces, deren Ports und Keys. Falls auch die Gegenstelle schon erreichbar ist, werden weitere Informationen angezeigt. Beispiel:
interface: wg-test public key: PecwpxwnSKPs4Gp39gvQzxdbZxQBCupB5Oo9OVM/5ko= private key: (hidden) listening port: 51820 peer: ZAleBcuJ4O9m2hfmz5bnqM0POCAIHQSsnWVBzreJaWw= endpoint: 193.202.123.89:51820 allowed ips: 0.0.0.0/0, ::/0 latest handshake: 37 seconds ago transfer: 125.24 MiB received, 140.72 MiB sent
Ob das Wireguard Modul geladen ist, kann mit dem Aufruf "lsmod | grep wireguard" ermittelt werden. Beispiel:
wireguard 221184 0 ip6_udp_tunnel 16384 1 wireguard udp_tunnel 16384 1 wireguard
macvtap
Ist das Interface in einer VM, die macvtap auf dem Host verwendet, um ein physikalisches Interface zu verwenden, kann es Probleme mit Multicast geben. (gilt nicht bei GRE (das verwendet ja auch kein macvtap :P) in einer VM sondern nur wenn das physikalische Interface verwendet wird, also eth0 oder eth1.6 oder... in den meisten Standardfällen daher uninteressant).
Näheres hier
In libvirt kann die Option trustGuestRxFilters='yes' an das entsprechende Interface gepackt werden, damit Multicast funktioniert:
<interface type='direct' trustGuestRxFilters='yes'> <source dev='enp1s0' mode='vepa'/> <model type='virtio'/> [..] </interface>
Testen der Konfiguration
Es kann in der Routingtabelle geguckt werden ob hier bereits routen vorhanden sind:
ip ro sh tab fff ip -6 ro sh tab fff
man kann sich mit nc mit Babel verbinden und sich Diagnoseausgaben anschauen:
nc ::1 33123
um mehr zu sehen, einfach dump eingeben und Enter drücken.
Per Script kann man das ganze z.b. so aufrufen:
echo "dump" | nc ::1 33123 -q 0
durch -q 0 wird nc direkt wieder beendet
Damit nc mit ipv6 funktioniert muss nc von den bsd Tools installiert werden:
apt-get install netcat-openbsd
Für eine bessere Übersicht hilft auch das Webinterface weiter (siehe weiter unten)
Richtlinien für Babel Penalty bei dezentralen Hoods
- Ethernet: 96
- Richtfunk
- >100Mbit: 256
- 30-100Mbit: 512
- 10-30Mbit: 1024
- bis 10Mbit: 4096
- VPN: 4096 - 16384
Je nach Situation können Links auch schlechter hier angegeben bewertet werden. Auf eine Aufwertung sollte jedoch verzichtet werden. Pro Link sollte maximal 16384 verwendet werden, damit auch bei vielen Hops das Maximum von 65535 nicht erreicht wird.
Begründung:
Wir wollen Richtfunkverbindungen (z.B. Marterlach -> St. Markus -> Hardhöhe -> Neunhof) gegenüber VPN (z.B. Marterlach -> per VPN zu einem HetznerGW -> per VPN nach Neunhof) bevorzugen, obwohl der Weg mehr Hops hat.
Metriken anpassen
Default Route auf einen Server bevorzugen
Da es nicht möglich ist, im Babel die Route zu bevorzugen (sonst wäre das System nicht mehr Loopsicher), können wir nur alle anderen default routen abwerten.
Dies machen wir durch einen Filter in der Babel Config.
Wir brauchen einen Inputfilter, der auf ip 0.0.0.0/0 eq 0 greift. Dazu das bevorzugte Interface ohne Penalty und alle anderen mit einem Penalty. Das ganze kann z.b. so aussehen
in ip 0.0.0.0/0 eq 0 if IF1 allow in ip 0.0.0.0/0 eq 0 if IF2 metric 384 in ip 0.0.0.0/0 eq 0 metric 2048
Zuerst wird auf das IF1 kein Penalty gegeben, danach auf IF2 ein Penalty von 384 und anschließend auf alle weiteren Interfaces ein Penalty von 2048.
WebUI für Babel
Babelweb
Für Babel gibt es ein WebUI. Quellen: https://github.com/kerneis/babelweb
Hinweis: Laut E-Mail von Gabriel Kerneis wird babelweb nicht mehr gepflegt, stattdessen wird der Nachfolger BabelWeb2 https://github.com/Vivena/babelweb2 weiter entwickelt! (Der folgende Text bezieht sich noch auf das ursprüngliche Babelweb 0.4.0.)
Installation:
apt install nodejs-legacy npm npm install -g babelweb
/etc/systemd/system/babelweb.service:
[Unit] Description=babelweb [Service] ExecStart=/usr/local/bin/babelweb Type=simple [Install] WantedBy=multi-user.target
Der Dienst wird registriert und gestartet mit
systemctl enable babelweb systemctl start babelweb
Modifikationen (optional):
Die Dokumentation von Babelweb empfiehlt, das Programm nicht als "root" laufen zu lassen. Manche möchten die Webseiten lieber über einen anderen Port als 8080 erreichen, zum Beispiel über Port 80. Leider benötigt BabelWeb root Rechte, um auf Ports < 1024 zuzugreifen (ein Linux-Feature). Beispiel, hier für einen eingeschränkten Benutzer "normalo" und Port 7070:
[Unit] Description=babelweb [Service] ExecStart=/usr/local/bin/babelweb port=7070 User=normalo Type=simple [Install] WantedBy=multi-user.target
Die Webseite optisch umgestalten ist auch möglich, der Einstiegspunkt ist
vi /usr/local/lib/node_modules/babelweb/static/index.html
Nach Änderungen in der Datei "babelweb.service" muss diese neu eingelesen werden mit
systemctl daemon-reload systemctl restart babelweb
Remote Server einbinden
Es muss ein SSH forwarding zu dem remote Gerät eingerichtet werden, gut erklärt in der Babel Doku: https://github.com/kerneis/babelweb/blob/develop/README.md unter "Monitoring remote babel instances". Danach die Datei server.js anpassen z.b.
[...] "routers" : "[::1]:33123,[::1]:33124,[::1]:33125", [...]
Achtung, keine Leerzeichen vor oder nach dem Komma benutzen!
Problem mit dem neuen Node
In Debian 9 wird keine vollwertige Node Version mehr angeboten, und das Node 0.x aus Debian 8 ist voller Sicherheitslücken. Abhilfe schafft der Download einer aktuellen Version aus Git, hier Node.js 8 LTS (Support bis mindestens Dezember 2019).
apt-get install curl curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - apt-get install -y nodejs npm install -g babelweb
Hinweis: Der Startlink ist nach dieser Installation "/usr/bin/babelweb", dies muss in /etc/systemd/system/babelweb.service gegenüber der Beschreibung im Absatz "WebUI für Babel" geändert werden.
Die letzte Babelweb Version 0.4.0 wurde bereits an die akuellen Node Versionen (>= 7) angepasst, aber eine Programmzeile vergessen. Deshalb muss eine Quellcode-Datei bearbeitet werden. Weiter entwickelt wird jetzt BabelWeb2, s.o.
vi /usr/lib/node_modules/babelweb/node_modules/policyfile/lib/server.js
Dort muss Zeile 254 geändert werden. Vorher:
Object.keys(process.EventEmitter.prototype).forEach(function proxy (key){
Nach Korrektur:
Object.keys(require('events').prototype).forEach(function proxy (key){
Quelle: https://github.com/LearnBoost/websocket.io/issues/55
Animation los werden
Ohne Animation lädt die Seite wesentlich schneller und auf schwachen Rechnern/Handys läuft die nicht gut. In
/usr/local/lib/node_modules/babelweb/static/index.html
folgende Zeilen auskommentieren:
</head> <body> <h1>BabelWeb</h1> <!-- <h2>Routers</h2> <div id="fig"> <p class="legend"> <span class="legend-title">Legend</span> <span class="legend-current">Current</span> <span class="legend-neighbour">Neighbours</span> <span class="legend-other">Others</span> </p> </div> --> <h3>Configuration</h3>
Babelweb in PHP
Eine alternative ist das Babelweb in PHP
Einfach diese File herunterladen und in das Webroot eines Webservers packen. PHP muss installiert sein:
https://github.com/rohammer/Simple-Babelweb
Eigenentwicklung der Freifunk Franken Community und es wird aktuell auch aktiv dran weiter entwickelt.
Beispiel: http://fff-jupiter.fff.community/Simple-Babelweb/
Mittlerweile ist auch ein einfaches Looking Glass https://de.wikipedia.org/wiki/Looking_Glass_(Internet) integriert