---
layout: page
title: Einstieg in Meshtastic
permalink: /blog/einstieg-in-meshtastic/
keywords: meshtastic,networking,ip tunneling,lora,rak wireless,rakwireless
description: Meine erste Erfahrung mit Meshtastic und ob und wie es möglich ist IP-Tunneling über Meshtastic zu betreiben.
lang: de
date: 2023-12-04
---

Neulich bin ich im Fediverse auf ein neues Projekt gestoßen: Meshtastic
Bei [Meshtastic](https://meshtastic.org/) handelt es sich um ein Peer-to-Peer Mesh-Netzwerk auf Basis von LoRa, einer proprietären Funktechnik.

Die Sache, welche mich besonders bei Meshtastic gelockt hat, ist, dass es [IP-Tunneling](https://github.com/meshtastic/python/issues/410) unterstützt. Ich habe immer wieder Spaß neue Routing- und Netzwerk-Technologien kennenzulernen und ich Meshtastic als eine gute Möglichkeit gesehen, etwas Neues zu lernen.

Um dem Netzwerk beizutreten, braucht man entsprechend ein LoRa-fähiges Gerät mit Meshtastic-Unterstützung. Wenn man nun etwas an einen Knoten senden möchte, sendet man dies in Nachrichten. Jede Nachricht hat einen Channel, auf welchen sie gesendet wird, einen Port, ein TTL und einen Inhalt. Die Nachrichten werden mithilfe von [Protobuf](https://protobuf.dev/) kodiert.

## Nachrichten

### Channel
Meshtastic benutzt zur Separierung [Channels](https://meshtastic.org/docs/configuration/radio/channels). Dabei gibt es einen Standard Channel, welcher öffentlich ist. Es können beliebig viele weitere hinzugefügt werden (bedingt durch Hardware aktuell nur acht). Die Channels haben Namen und, wenn gewünscht, ein Password. Die Nachrichten werden dann mit AES256-CTR (manche Geräte haben dafür auch Hardware-Unterstützung) [verschlüsselt](https://meshtastic.org/docs/overview/encryption). Jedes Gerät, welches an dem Channel teilnimmt und entsprechend auch das Password weiß, kann die Nachricht wieder entschlüsseln.
Des Weiteren wird in einen "primären" und mehrere "sekundäre" Channels unterschieden. Der primäre Channel wird für das Verteilen von Knoteninformationen (Laufzeit, Standort, Akkustand, ...) und für IP-Tunneling verwendet. Auf den sekundären Channels können lediglich Nachrichten ausgetauscht werden.

### Port
Jede Meshtastic-Nachricht beinhaltet des Weiteren einen [Port](https://github.com/meshtastic/python/issues/465#issuecomment-1824842585). Dieser gibt darüber Auskunft, was die Nachricht beinhaltet (Textnachricht, Knoteninformation, IP-Paket, ...)

### TTL
Der Mesh-Algorithmus ist recht einfach und implementiert das Prinzip des "Floodings". Jeder Knoten sendet jedes Paket an seinen benachbarten Knoten. Dieser sendet das Paket dann entsprechend weiter. Bei der Weiterleitung des Paketes wird das TTL um eins reduziert. Das Standardmäßige TTL ist 3 - es kann aber bis auf 7 gesetzt werden. Ein Paket mit einer TTL von 0 wird nicht weitergeleitet.

## Hardware
Ich persönlich bin eher der Software-Mensch statt Hardware. Ich finde, Hardware kann recht unberechenbar sein und das Schlimmste von allem: Es zeigt nicht einmal Fehlermeldungen an.
Ich brauchte also ein recht einfaches Gerät. Da ich IP-Tunneling machen wollte, brauchte ich sogar mindestens zwei. Da ich aktuell Student bin, müssen die beiden Geräte auch günstig sein. Und da ich ein recht unordentlicher Mensch bin, brauche ich auch eine Hülle bzw. ein Gehäuse für die Geräte. Meshtastic bietet auf ihrer Website eine [Liste mit Geräten](https://meshtastic.org/docs/hardware) an. Ich habe mir die Geräte angeschaut und mich schlussendlich für das [Meshtastic Starter Kit](https://store.rakwireless.com/products/wisblock-meshtastic-starter-kit) von [RAKwireless](https://www.rakwireless.com/) entschieden.

![Man kann weiße Tüten mit braunen Schildern darauf sehen. Auf den braunen Schildern steht unter anderem "RAK".](/assets/img/meshtastic-einstieg/gereate_verpackt_von_hinten.jpg)

![Man sieht zwei weiße Tüten. Sie sind vor der Seite des Fotos transparent. In der linken Tüte sieht man einen blauen Zettel, auf welchem eine Platine liegt. In der rechten Tüte sind man etwas Plastik (Batteriehalterung), Pads, welche als Füße fungieren, ein paar Plastik Teile sowie Schrauben.](/assets/img/meshtastic-einstieg/gereate_verpackt_von_vorne.jpg)

Danach kam die Herausforderung des Zusammenbauens. Glücklicherweise bietet RAKwireless eine [Dokumentation](https://docs.rakwireless.com/Product-Categories/Accessories/RAKBox-B5/Installation/) dafür an.

![Man sieht eines der Plastikteile. Es ist unter anderem ein Bereich markiert, in welchem "WisBase" steht.](/assets/img/meshtastic-einstieg/gehause_nackt.jpg)

![Man sieht das Plastikobjekt, wo eine Platine mit Abstandshaltern darauf liegt. An der Platine sind zwei Kabel angebracht, welche wiederum zu jeweils einer kleinen Platine führen (das sind die Antennen).](/assets/img/meshtastic-einstieg/beim_zusammenbauen_von_seite.jpg)

![Man sieht das vorherige Foto aus einer schrägen Perspektive.](/assets/img/meshtastic-einstieg/beim_zusammenbauen_kern_liegt.jpg)

![Man sieht ein transparentes durchsichtiges Acryl-Gehäuse (die Plastikteile von eben) in welchem eine Platine ist. Von der Platine führen zwei Kabel ab, welche jeweils an einer anderen Platine angebracht sind. Die zwei Platinen sind auf dem Boden des Acryl-Gehäuses festgeklebt. Man sieht ein Kabel von der Hauptplatine ausgehen. Auf dieser leuchten zwei LEDs - eine Rote, eine Grüne.](/assets/img/meshtastic-einstieg/eingebaut.jpg)

Nachdem ich die Antennen an dem Board befestigt hatte und in das Gehäuse verschraubt hatte, stellte ich allerdings fest, dass am Gehäuse Schutzfolien waren. Davon war nichts in der Dokumentation erwähnt. Dies bedeutete für mich also, dass ich alles noch einmal abschraubte und wieder zusammenschrauben musste.

Des Weiteren waren nicht genug Schrauben mitgeliefert. Für das Gebäude mit allen möglichen Add-ons braucht man 12 Schrauben, mein Setup ohne Batterie-Halterung braucht 8 Schrauben - mitgeliefert waren aber nur 6 Schrauben.

Ein weiteres Hindernis war die Befestigung der Antennen am Gehäuse. Die Bluetooth-Antenne hat ein kleines Pad mit Kleber, jedoch nicht die LoRa-Antenne. Nachdem ich jedoch wegen der Schutzfolien alles neu zusammengeschraubt war, konnte ich das Klebepad der Bluetooth-Antenne auch nicht mehr verwenden. Ich habe mich dazu entschieden, etwas Heißkleber zu verwenden und die Antennen damit zu verfestigen. Da ich mich nicht mit Hardware auskenne, weiß ich nicht, wie gut diese Idee war - ich weiß nur, dass es bei mir glücklicherweise nichts kaputt gemacht hat.

## Einrichtung

Danach war die Einrichtung der Geräte dran. Meshtastic bietet dazu ein in Python geschriebenes [Kommandozeilen-Tool](https://meshtastic.org/docs/software/python/cli), eine [Weboberfläche](https://meshtastic.org/docs/software/web-client) (die funktionierte bei mir nicht) und eine [Android-App](https://meshtastic.org/docs/category/android-app). Ich habe mich für das Kommandozeilen-Tool entschieden.
Das Gerät wurde jedoch nicht richtig durch das Tool erkannt. Die Android-App konnte mir auch den Grund erklären: Die Firmware ist zu alt.

Ich habe daraufhin ein "Factory Reset" gemacht und danach die aktuelle Firmware hochgeladen. Mit dem "Factory Reset" wollte ich sicherstellen, dass keine alten Konfigurationsschnipsel von RAKwireless da waren.

## IP-Tunneling

Nachdem ich alles eingerichtet habe, war es an der Zeit, die IP-Tunneling-Funktion auszuprobieren:
```
$ sudo meshtastic --tunnel
Connected to radio
INFO file:tunnel.py __init__ line:83 Starting IP to mesh tunnel (you must be root for this *pre-alpha* feature to work).  Mesh members:
INFO file:tunnel.py __init__ line:95 Node !5687b499 has IP address None.180.153
INFO file:tunnel.py __init__ line:95 Node !148bfdc5 has IP address None.253.197
sh: line 1: ifconfig: command not found
Aborting due to: 
```

[Auf meinem Computer war ifconfig nicht installiert](https://github.com/meshtastic/python/issues/467). ifconfig ist ein altes Tool, welches früher zur Netzwerkkonfiguration verwendet wurde. Heutzutage wird allerdings empfohlen, `ip` zu verwenden.

Nachdem ich ifconfig installiert hatte, habe ich das Ganze noch einmal ausprobiert:
```
$ sudo meshtastic --tunnel
Connected to radio
INFO file:tunnel.py __init__ line:83 Starting IP to mesh tunnel (you must be root for this *pre-alpha* feature to work).  Mesh members:
INFO file:tunnel.py __init__ line:95 Node !5687b499 has IP address None.180.153
INFO file:tunnel.py __init__ line:95 Node !148bfdc5 has IP address None.253.197
None.180.153: Unknown host
ifconfig: `--help' gives usage information.
Aborting due to: ifconfig command failed.
```

Scheinbar wird ifconfig aufgefordert die IP-Adresse `None.180.153` zu konfigurieren. [Dies liegt daran, dass die App fehlerhaft ist](https://github.com/meshtastic/python/issues/468). Hintergrund ist, dass das Kommandozeilenargument zur Festlegung des Subnets verwendet wird. Wenn man allerdings kein Subnet angibt, ist das Argument `None`.

Ein möglicher Workaround ist:
```
$ sudo meshtastic --tunnel --subnet 10.115
```

Daraufhin konnte das Interface gestartet werden:
```
$sudo meshtastic --tunnel --subnet 10.115
Connected to radio
INFO file:tunnel.py __init__ line:83 Starting IP to mesh tunnel (you must be root for this *pre-alpha* feature to work).  Mesh members:
INFO file:tunnel.py __init__ line:95 Node !148bfdc5 has IP address 10.115.253.197
INFO file:tunnel.py __init__ line:95 Node !5687b499 has IP address 10.115.180.153
```
```
$ ip address show mesh0
22: mesh0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 200 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 10.115.253.197/16 scope global mesh0
       valid_lft forever preferred_lft forever
```

Ich habe zur Behebung des Fehlers daraufhin eine PR gestellt.

Das Subnet `10.115.0.0/16` ist im privaten Bereich und kann daher eigentlich ohne Probleme verwendet werden. Da das [dn42](https://dn42.dev/Home) und die damit verbundenen Netzwerk jedoch auch Netze in diesem Bereich verwenden, habe ich nach Kollisionen gesucht und leider eine gefunden. Das Freifunk Cuxhaven verwendet ungünstigerweise auch diesen Netzbereich. Da diese jedoch nicht mehr im IC-VPN sind, habe ich eine [PR](https://github.com/freifunk/icvpn-meta/pull/635) erstellt, um das Netzwerk zu entfernen. Mein eigenes dn42-Netzwerk habe ich angewiesen, den Bereich `10.115.0.0/16` als ungültig zu betrachten und damit nicht zu routen.

Ein weiteres Hindernis beim IP-Tunneling mit Meshtastic ist das kleine MTU von 200 Bytes.
Dies verhindert automatisch IPv6, da IPv6 eine MTU von mindestens 1280 Bytes erfordert. Es ist jedoch möglich, IPv6 über IPv4 zu tunneln (GRE, WireGuard, ...).

Für das IP-Tunneling [wird immer der primäre Channel verwendet](https://github.com/meshtastic/python/issues/465). Eine Änderung ist aktuell nicht geplant. Dies bedeutet jedoch, dass eine Verschlüsselung schwierig wird:
- Wenn man einen privaten Channel mit zufälligem Password als primären Channel festlegt, sind die IP-Pakete zwar verschlüsselt, jedoch bekommen andere Knoten keine Knoteninformationen mehr, welche auch über Broadcast verteilt werden.
- Wenn man die IP-Pakete im öffentlichen Standard-Channel tunnelt, teilt und bekommt man zwar weiterhin die Knoteninformationen, die IP-Pakete sind aber nicht verschlüsselt.
    - Eine Möglichkeit dieses Problem zu umgehen und IPv6 zu verwenden, wäre einen WireGuard Tunnel (oder vergleichbares) zu verwenden.

Ein Weiteres Problem beim IP-Tunneling über Meshtastic die die hohe Latenz und der Paketverlust:
```
$ time ping 10.115.253.197 -c 20 -W 600
PING 10.115.253.197 (10.115.253.197) 56(84) bytes of data.
64 bytes from 10.115.253.197: icmp_seq=1 ttl=64 time=12612 ms
64 bytes from 10.115.253.197: icmp_seq=2 ttl=64 time=15457 ms
64 bytes from 10.115.253.197: icmp_seq=4 ttl=64 time=14536 ms
64 bytes from 10.115.253.197: icmp_seq=5 ttl=64 time=14669 ms
64 bytes from 10.115.253.197: icmp_seq=6 ttl=64 time=14803 ms
64 bytes from 10.115.253.197: icmp_seq=8 ttl=64 time=17756 ms
64 bytes from 10.115.253.197: icmp_seq=9 ttl=64 time=19245 ms
64 bytes from 10.115.253.197: icmp_seq=10 ttl=64 time=19234 ms
64 bytes from 10.115.253.197: icmp_seq=11 ttl=64 time=19280 ms
64 bytes from 10.115.253.197: icmp_seq=12 ttl=64 time=19564 ms
64 bytes from 10.115.253.197: icmp_seq=14 ttl=64 time=21571 ms
64 bytes from 10.115.253.197: icmp_seq=16 ttl=64 time=21286 ms
64 bytes from 10.115.253.197: icmp_seq=17 ttl=64 time=21525 ms
64 bytes from 10.115.253.197: icmp_seq=20 ttl=64 time=29039 ms

--- 10.115.253.197 ping statistics ---
20 packets transmitted, 14 received, 30% packet loss, time 19209ms
rtt min/avg/max/mdev = 12611.611/18612.706/29038.582/4040.933 ms, pipe 16

real	0m50.196s
user	0m0.007s
sys	0m0.068s
```

Auch eine UDP-Übertragung war auch problemlos möglich:
```
$ ncat --verbose --wait 10m --udp 10.115.180.153 8886
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Connected to 10.115.180.153:8886.
Hello World!
^C
```
```
$ ncat --listen --verbose --udp --source-port 8886
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Listening on [::]:8886
Ncat: Listening on 0.0.0.0:8886
Ncat: Connection from 10.115.253.197:47920.
Hello World!
^C
```

Eine einfache TCP-Verbindung war jedoch nicht möglich. Somit kann Meshtastic auch nicht für das dn42 eingesetzt werden. Einfache Chat-Anwendungen, welche auf UDP basieren und hohe Latenzen vertragen, sollten allerdings möglich sein.
```
$ ncat --verbose --wait 10m 10.115.180.153 8886
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Connection timed out.
```

![Man kann einen Ausschnitt aus WireShark sehen. Es zeigt eine einige TCP retransmissions zwischen 10.115.180.153 und 10.115.253.197 an.](/assets/img/meshtastic-einstieg/wireshark_tcp_retransmission.png)
