Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

5 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ’๐Ÿ’๐Ÿ’ WILDFLORA ๐Ÿ’๐Ÿ’๐Ÿ’

Heltec LoRa WiFi V4.3 โ€” TCP/IP over LoRa

Real TCP/IP networking over LoRa between two Linux hosts, using Heltec WiFi LoRa 32 V4 boards (ESP32-S3 + SX1262) flashed with RNode firmware and bridged via tncattach. Secured with WireGuard.

Architecture

Linux host A โ”€โ”€USBโ”€โ”€ Heltec V4 #1 โ‡„ LoRa โ‡„ Heltec V4 #2 โ”€โ”€USBโ”€โ”€ Linux host B
   tncattach (tnc0)                              tncattach (tnc0)
   10.0.0.1                                       10.0.0.2
       โ†• WireGuard wg1 (encrypted) โ†•
   10.99.0.1                                      10.99.0.2

Each Heltec becomes a KISS TNC modem. tncattach exposes it as a Linux kernel network interface (tnc0). WireGuard (wg1) encrypts all traffic on the link.

Verified performance (live test, host A โ†” host B)

Metric Value Conditions
Packet loss 0% (20/20 ICMP, 5/5 ping) SF7 / 125 kHz / 7 dBm, desk range
RTT (raw IP) 187โ€“534 ms (median 220 ms) 868 MHz, USB-serial KISS
RTT (WireGuard) 1.2โ€“2.0 s WG handshake + encrypted ICMP
Throughput ~0.9 kbps app-level stop-and-wait, 32B payload
TCP handshake 0.40 s 3-way handshake + echo
SSH session end-to-end success SSH < WireGuard < IP < KISS < LoRa
Firmware RNode v1.86 (markqvist upstream) Not CE fork, not microReticulum

Files

install-rnode-lora.sh          Wizard installer/uninstaller (801 lines)
tests/kisstest.py              KISS frame round-trip test (Aโ†”B)
tests/iptest.py                Real IP/ICMP packet test over LoRa
tests/reliability.py           RTT/loss/throughput characterization
tests/sandbox-test.sh          Isolated netns test harness (17 tests)

Quick start

Prerequisites

  • Two Heltec WiFi LoRa 32 V4 boards (ESP32-S3 + SX1262)
  • Two Linux hosts (tncattach is Linux-only โ€” no macOS support)
  • USB-C data cables connecting each board to its host

Install (on each host)

sudo ./install-rnode-lora.sh

The wizard will:

  1. Install dependencies (git, build-essential, python3-pip, wireguard-tools, rns)
  2. Detect the board on /dev/ttyACM*
  3. Verify/flash RNode firmware (offers rnodeconf --autoinstall if needed)
  4. Set TNC mode + radio params (defaults: 868 MHz / 125 kHz / SF7 / CR5 / 7 dBm)
  5. Build + install tncattach, bring up tnc0
  6. Configure WireGuard wg1 (generates keys, prints public key for peer)
  7. Open firewall for tnc0 + wg1
  8. Verify the link (ping peer)
  9. Optionally create systemd units for reboot persistence
  10. Snapshot pre-install state (wg configs, firewall, routing) for rollback

Run on host A first, note the printed public key, then run on host B with mirrored IPs and host A's public key.

Commands

sudo ./install-rnode-lora.sh              # interactive wizard
sudo ./install-rnode-lora.sh install      # force install
sudo ./install-rnode-lora.sh uninstall    # remove + restore pre-install state
sudo ./install-rnode-lora.sh status       # show current state (read-only)
sudo ./install-rnode-lora.sh --dry-run install     # print actions, mutate nothing
sudo ./install-rnode-lora.sh --dry-run uninstall

Uninstall

sudo ./install-rnode-lora.sh uninstall

Restores the host to its pre-install state using the snapshot:

  • Restores WireGuard configs (e.g. wg0.conf) verbatim from snapshot
  • Removes only tnc0/wg1 firewall rules (leaves fleet/NetBird rules untouched)
  • Re-brings-up any WireGuard interface that was running before install
  • Removes tncattach binary, wg1.conf, logs, state, snapshot
  • Offers to restore the board to Normal mode (rnodeconf -N)
  • Does NOT remove shared deps (git, wireguard-tools) by default

Test the sandbox

sudo tests/sandbox-test.sh install-rnode-lora.sh

Runs 17 tests in an isolated network namespace โ€” never touches the live host network.

Radio parameters (SSOT)

All values are readonly constants at the top of install-rnode-lora.sh:

Parameter Default Notes
Frequency 868 MHz (863โ€“870 MHz EU band) Must match on both boards
Bandwidth 125 kHz
Spreading factor SF7 (fastest) SF11 = longest range, ~937 bps
Coding rate 4/5
TX power 7 dBm Board max 28 dBm; low for desk range
Serial baud 115200 RNode firmware default
tnc0 MTU 496 RNode P2P (500 โˆ’ 4)
wg1 MTU 400 tnc0 496 โˆ’ ~80 WireGuard overhead
wg1 port 51821 Avoids default 51820 + fleet

Security

The raw KISS IP link is unencrypted. Two layers secure it:

  1. WireGuard (wg1) โ€” encrypts all IP traffic on the LoRa link. Handshake (Curve25519) completes over LoRa (~1 s at SF7). A LoRa eavesdropper sees only encrypted UDP noise.
  2. SSH โ€” end-to-end encryption + host-key auth, independent of the VPN. Sufficient if SSH is the only application.

Both were tested live: WG handshake completed, encrypted ICMP traversed the tunnel, and an interactive SSH-over-WG-over-LoRa session ran successfully.

What this is NOT

  • Not Meshtastic โ€” the original Meshtastic 2.7.26 firmware was reflashed; private keys are unrecoverable, so reflashing Meshtastic again creates new node identities.
  • Not Reticulum โ€” Reticulum is its own L3 stack (announces, LXMF, rnsh), not TCP/IP. The jrl290/RTNode-HeltecV4 and microReticulum firmwares carry Reticulum, not IP.
  • Not fast โ€” LoRa at SF7 gives ~0.9 kbps app-level. Usable for ping, text, laggy SSH. Not for bulk transfer, web, or NetBird.
  • Not standalone โ€” the Heltec is a KISS modem, not an IP node. A Linux host provides the IP stack via tncattach. There is no native ESP32 lwIP-over-LoRa firmware.

Key decisions (why this stack)

Question Answer Why
Which firmware? RNode v1.86 (markqvist upstream) Supports Heltec V4 + KISS TNC mode; CE fork doesn't support V4
Why not microReticulum? Reticulum โ‰  TCP/IP It's its own network stack, no ifconfig, no sockets
Why not WiFi-KISS? Untested live Firmware exposes KISS-over-TCP on port 7633, but we used USB-serial (more reliable, boards are USB-attached)
Why wg1 not wg0? wg0 = fleet NetBird uses wt0; legacy WG hub uses wg0. Never touch fleet interfaces.
Why MTU 496? RNode P2P Radio MTU 500 โˆ’ 4 bytes KISS P2P header

Tested hardware

  • Board: Heltec WiFi LoRa 32 V4.3 (ESP32-S3FH4R2, 16 MB flash, 2 MB PSRAM, SX1262 + KCT8103L PA)
  • Firmware: RNode v1.86, heltec32v4pa build, TNC mode
  • Hosts: host A (x86-64, Ubuntu 6.8 kernel) + host B (aarch64 Jetson)

Restoring Meshtastic (if needed)

Reflash via the Meshtastic web flasher (Chrome/Edge). New node identities will be generated on reflash (the original keys are unrecoverable).

About

๐Ÿ’Heltec LoRa WiFi V4.3 โ€” TCP/IP over LoRa๐Ÿ’

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages