feat: wire packet tap for sniffer/debug consumers#10
Open
rinchen wants to merge 1 commit into
Open
Conversation
Add PacketTapEvent/PacketTapDirection, TransportMessage::SetPacketTap, RX/TX emission in the transport actor, and ReticulumHandle::register_packet_tap for embedders that need wire-level observation (e.g. mesh-client sidecar sniffer).
rinchen
added a commit
to Colorado-Mesh/mesh-client
that referenced
this pull request
Jul 2, 2026
- Add reticulum-sidecar/patches/rsReticulum-packet-tap.patch (base 6d2b284) exposing PacketTapEvent and register_packet_tap for the wire sniffer; upstream PR ratspeak/rsReticulum#10. - Pin RS_RETICULUM_REF and apply the patch in build-rns-stack and build-windows-arm64-rns-stack workflow jobs before cargo build. - Add scripts/apply-rsReticulum-packet-tap.sh and document the overlay in reticulum-sidecar/README.md and patches/README.md. CI was failing E0432/E0425/E0599 because live.rs calls packet-tap APIs that upstream rsReticulum main does not ship yet; the vendored overlay unblocks all four rns-stack matrix jobs without removing sniffer wiring.
rinchen
added a commit
to Colorado-Mesh/mesh-client
that referenced
this pull request
Jul 2, 2026
…, RNode flasher/BLE/Wi-Fi, triple-protocol BLE, peer graph overhaul & repo-wide i18n (Fixes #593) (#596) feat: add Reticulum as third protocol tab alongside Meshtastic and MeshCore Completes #593 — adds a headless Rust mesh-client-reticulum sidecar (AGPL, axum HTTP + WebSocket), Electron reticulum:* IPC, and full React UI with Ratspeak/rsReticulum/rsLXMF wire interop as primary compatibility target. 469 files changed, 68,834 insertions(+), 4,849 deletions(-) ── Rust sidecar (reticulum-sidecar/) ────────────────────────────────── Binary: mesh-client-reticulum — axum HTTP + WebSocket event bridge. API modules: status, app info, interfaces CRUD, contacts, LXMF send/resource/reaction/delete, config import/export/audit/repair, diagnostics, factory reset, propagation sync, nomad list/favorite/page/file, topology edges, packet tap ring buffer (GET/DELETE /api/v1/packets, wire_packet WS events), voice/games status stubs, BLE scan/availability, serial port enumeration. Cargo features: optional rns-stack; rns-ble (BLE Peer + ble:// RNode); rns-rnode-tcp (Wi-Fi tcp:// RNode). Dev auto-build enables rns-stack,rns-ble when Ratspeak siblings present at ../../rsReticulum, ../../rsLXMF. Live stack bridge: async reads (no blocking_read panics); timed transport control queries (8 s cap) with cache fallback; LinkDeliveryManager for async LXMF (Direct vs Propagated); Nomad page/file via LinkClient::query with identity-hash resolution; LXMF attachment send/receive; propagation bridge for live sync. Packet tap: register_packet_tap from rsReticulum → wire_packet WS + sniffer buffer. Vendored patch reticulum-sidecar/patches/rsReticulum-packet-tap.patch (upstream ratspeak/rsReticulum#10) applied in CI before rns-stack builds. Config: validated atomic writes, extra_sections round-trip, 4 MiB body limit, mnemonic stripped on disk, localhost CORS, loopback bind guard. Interface health: merge config rows with live GetInterfaceStats so failed RNode/KISS interfaces remain visible; preset expansion/repair on bootstrap; coordinated RNode RF profiles; enabled preserved when live stats omit offline BLE RNodes. CI: dual matrix — stub builds (no siblings) on all platforms + rns-stack on linux x64, macOS arm64, Windows x64+arm64. libdbus-1-dev for Ubuntu rns-ble. cargo test in workflow. electron-builder extraResources. Dev: pnpm run reticulum:sidecar:build; auto-rebuild when Rust sources newer than binary; sidecar survives dev HMR remounts. ── Electron main process + preload ──────────────────────────────────── ReticulumSidecarManager — spawn, health poll, serialized start (coalesce concurrent reticulum:start), HTTP proxy GET/POST/PUT/DELETE, WS event bridge to renderer. reticulum:* IPC — proxy routes with path allowlist (/api/v1/), transport-aware timeouts (30 s for peers/interfaces/topology/packets; Nomad page/file uses max(egress, RF) up to 180 s), config file read/import dialog. SQLite IPC — Reticulum message search (FTS5 schema v41), delete, attachment save/show-in-folder (path jail), peer/contact delete, db:clearReticulumMessages, chat outbox attempt_count persistence. ble-coexistence-coordinator.ts — peripheral MAC registry, scan-only mutex (noble / reticulum / webbt); Noble pause/resume for Reticulum picker scans without dropping GATT; rejects same-MAC conflicts. mqtt-client-teardown.ts — absorbs late mqtt.js connack/keepalive errors on force-disconnect (fixes uncaught main-process exceptions). Security hardening (manual audit): validateIpcSender on reticulum/vault/DB/BLE handlers; attachment path jail; proxy body/config read caps; vault 8-char passcode + unlock rate limiting; bounded readUtf8FileBounded (TOCTOU fix). ── Renderer — Reticulum protocol integration ───────────────────────── Registered in meshProtocol, ProtocolCapabilities, theme (amber), useReticulumRuntime, useReticulumSession, SQLite migrations (v39+), hydrateIdentityStoresFromDb, useReticulumPanelActions. Capability-gated UI — hasReticulum*, hasLxmfDeliveryStatus, etc.; check-protocol-string-gates extended; no raw protocol === 'reticulum' checks in new code. Canonical stores — reticulumIngest → messageStore; nodeStore canonical for Reticulum UI; reticulumPeerStore for favorites/names; deduplicated sidecar reads (reticulumSidecarReads), peer display names, chat last-read migration, unread counting. Runtime — WS subscriptions for wire_packet, LXMF delivery, peers_updated, propagation sync_progress, interface.state; autostart/reconnect on unexpected stop; debounced event refreshes (2 s) during Nomad browsing. Header — green "configured" status when stack running; identity display name from sidecar (not uint32 fallback); ConnectIcon during connecting. ── Tab layout & panel architecture ─────────────────────────────────── Connection tab → ReticulumStackPanel — stack start/stop, auto-start, Disconnect & quit; Interfaces section (CRUD, device pickers, offline alerts) — collapsed by default Network tab → ReticulumNetworkPanel — identity gen/import/export/switch, announce interval, propagation mode, config import/export, stack settings Admin tab → ReticulumAdminPanel — RNode firmware flasher, Wi-Fi provisioning (WifiConfig.tsx), factory reset Peers tab → ReticulumPeerListPanel — Peers | Contacts sub-tabs, search, sort, virtual scroll, path/probe/favorite/chat, detail modal Chat tab → shared ChatPanel — DM-only LXMF; contact tabs; transport badges; outbox; search; attachments; voice clips; reactions Topology tab → ReticulumTopologyPanel — hierarchical graph: self → interface hubs → peers; distant-peer filters Nomad tab → NomadNetworkPanel — Favourites/Announces, Micron HTML browser, file downloads Diagnostics tab → shared + ReticulumDiagnosticEngine — Reticulum-native rows (no LoRa hop-goblin semantics); config audit hints; unified ping panel Sniffer/Stats → shared RawPacketLogPanel — Reticulum wire_packet variants; Graph tab hidden for Reticulum Meshtastic/MeshCore Radio, Map, Modules, and Graph tabs restored after Reticulum capability gating (appTabMappings OR rule fix). ── Connection tab — interface management ────────────────────────────── CRUD: add, edit (inline form: name, TCP host/port, RNode serial/preset/ callsign/RF params, BLE seed addresses, Wi-Fi host/port), enable/disable, delete with ConfirmModal. Device pickers: ReticulumInterfaceDevicePickerModal for serial, BLE Peer, BLE RNode; Electron serial picker with known/last-used port labels. Transports: USB serial, ble:// RNode, tcp://host[:7633] Wi-Fi RNode (not TCP Client 4242), BLE Peer mesh, Auto, TCP/UDP, KISS, Pipe, I2P, RNode Multi. Health UI: reticulumLocalInterfaceHealth classifier (stale_port vs enabled_down); Connection alert banner with Open Network / Refresh ports; cyan "connecting" grace window (30 s post-start) for BLE RNode link settle; adaptive 5 s/30 s polling; stack restart on serial CRUD or RF patch changes. Config audit/repair: sidecar GET /config/audit, POST /config/repair; diagnostics merge; Connection hints with repair/disable/deep-link edit via reticulumUiStore. RNode RF edit: frequency, bandwidth, spreading factor, coding rate, TX power; coordinated preset defaults; stack restart on RF changes. ── LXMF chat (DM-only) ─────────────────────────────────────────────── DM tabs from LXMF contacts even without prior message history; auto-select first contact; block send without recipient. Transport badges: RF / TCP / NET in and out on messages (received_via / sent_via columns, sidecar egress classification). Delivery status: outbound "Sending" until lxmf_outbound_status / LinkDeliveryManager events; propagation-node badge and toast when offline without PN. Threading: ratspeak.chat.v2 reply hashes; dismiss closed DM tabs across restarts; clear DM history via App danger zone (db:clearReticulumMessages). Attachments: live LXMF file send/receive; [file:...] rendering; save/show-in-folder IPC; chunked upload. Voice clips: record in ChatComposer, playback/cache. Reactions: live LXMF reactions on rns-stack path. Outbox: persist attempt_count; drain on announce, path updates, MQTT reconnect (chatOutboxDrain). Search: FTS5 message search in SearchModal. Payload limit: 4096 bytes via ProtocolCapabilities.lxmfPayloadLimit. ── Peers, contacts & identity ──────────────────────────────────────── Dedicated Peers tab (not NodeListPanel fork): path, probe, favorite, open DM, copy hash (Electron clipboard IPC). reticulumPeerStore + SQLite destination persistence; peers_updated WS after path/probe; footer peer count synced from path table. Identity: generate, import (ratspeak.identity.v2), export (passphrase required), multi-identity switcher, announce interval, clear announces, profile icons from LXMF FIELD_ICON_APPEARANCE, blocked contacts, identity activity store. Peer detail modal: avatar colors; voice-call button removed (LXST not implemented). ── Nomad Network browser ───────────────────────────────────────────── Sidecar ingests nomadnetwork.node announces; persists nodes with identity_hash for LinkClient::query. UI: split list + browser pane; Micron HTML via micron-parser + NomadMicronPageView (DOMPurify); source toggle; in-page and cross-node navigation. Downloads: /file/ fetches with base64 IPC round-trip; transport-aware timeouts (TCP 45 s, RF hop-scaled up to 180 s). Resilience: 5 s TTL cache for interfaces GET; 60 s egress cache; skip caching network egress when interfaces list empty; proxy timeout uses max(egress, RF) so RF page fetches are not aborted at 47 s. ── Network topology graph (Reticulum) ──────────────────────────────── MeshChat-style hierarchical layout: local identity center → configured interface hubs (human-readable names) → peers hung off matching interface. Show all configured interfaces as spokes even when idle; green/red online/offline styling. Distant-peer filters (show distant peers, max hops); enrich labels from peers, contacts, Nomad announces. buildReticulumViaHashEdges for hub-to-leaf edges when API returns nodes but empty edges array. Force-directed fallback replaced by structured layout; full-height mount without nested scroll. ── Wire packet sniffer & Stats (all protocols) ─────────────────────── Reticulum: sidecar packet tap → wire_packet WS → rawPackets store; clearRawPackets IPC. Pause-to-inspect: Wireshark-style Pause/Resume with pending count; snapshot packets while paused; jump-to-latest when unpinned. Batch ingestion: wire_packet appends batched per animation frame. Scroll pinning: align with ChatPanel contract (anchorTo: 'end', followOnAppend); unpin on scroll-up/wheel/expand; preserve anchor when reading history. Virtualizer keys: rawPacketContentKey / getItemKey — no duplicate React keys for identical captures. Duplicate sniffer rows fixed (removed dual handleSidecarEvent subscription in ReticulumStackPanel). Stats/Sniffer panels enabled for Reticulum with RawPacketLog Reticulum variants; Graph tab removed for Reticulum ▣ Build · Big Pickle · interrupted feat: add Reticulum as third protocol tab alongside Meshtastic and MeshCore Completes #593: Rust sidecar (axum HTTP+WS), Electron reticulum:* IPC, and full React UI with Ratspeak/rsReticulum/rsLXMF wire interop. 469 files, 68,834 insertions. ── Sidecar (reticulum-sidecar/) ── Binary mesh-client-reticulum with optional rns-stack, rns-ble, rns-rnode-tcp. Async live-stack bridge (no blocking_read panics), LinkDeliveryManager for async LXMF, Nomad page/file via LinkClient::query, register_packet_tap → wire_packet WS + sniffer buffer. Vendored rsReticulum patch for packet tap. Config atomic writes, 4 MiB body limit, localhost CORS. CI dual matrix (stub + rns-stack). pnpm run reticulum:sidecar:build; survives HMR remounts. ── Main / preload ── ReticulumSidecarManager (spawn, health poll, serialized start, HTTP proxy, WS bridge). reticulum:* IPC with path allowlist, transport-aware timeouts (30 s general, 180 s Nomad RF). SQLite FTS5 message search (v41), attachment path jail. ble-coexistence-coordinator — triple-protocol BLE MAC registry + scan mutex without dropping GATT. mqtt-client-teardown absorbs late connack errors. Security: validateIpcSender, vault rate limiting, bounded file reads. ── Renderer integration ── Registered in meshProtocol, ProtocolCapabilities, theme (amber), useReticulumRuntime, useReticulumSession, SQLite migrations v39+. Capability-gated UI (hasReticulum*, hasLxmfDeliveryStatus); no raw protocol === 'reticulum'. reticulumIngest → messageStore; reticulumPeerStore for favorites/names. WS subs for wire_packet, LXMF delivery, peers_updated, propagation, interface.state. Autostart/reconnect on unexpected stop. Header shows identity display name, not uint32 fallback. ── Tab layout ── Connection → ReticulumStackPanel — start/stop, auto-start, interface CRUD Network → ReticulumNetworkPanel — identity gen/import/export/switch, announce, propagation, config import/export Admin → ReticulumAdminPanel — RNode nRF52 DFU + ESP32 flasher, Wi-Fi provisioning, factory reset Peers → ReticulumPeerListPanel — Peers | Contacts, search, sort, virtual scroll, path/probe/favorite/chat, detail modal Chat → shared ChatPanel — DM-only LXMF, transport badges, outbox, search, attachments, voice clips, reactions Topology → ReticulumTopologyPanel — hierarchical graph: self → hubs → peers, distant-peer filters Nomad → NomadNetworkPanel — Favourites/Announces, Micron HTML browser, file downloads Diagnostics → shared + ReticulumDiagnosticEngine — native rows, config audit hints, unified ping panel Sniffer → shared RawPacketLogPanel — wire_packet variants Meshtastic/MeshCore Radio, Map, Modules, Graph tabs restored after capability OR fix. ── Interfaces (Connection tab) ── CRUD inline form: name, TCP host/port, RNode serial/preset/RF, BLE seed addresses, Wi-Fi host/port. Device pickers for serial, BLE Peer, BLE RNode. Transports: Auto, TCP/UDP, KISS, Pipe, I2P, RNode (USB/ble:///tcp:// Wi-Fi), RNode Multi, BLE Peer. Health classifier (stale_port vs enabled_down); cyan 30 s grace for BLE RNode settle; adaptive polling. Config audit/repair from sidecar; deep-link edit via reticulumUiStore. RNode RF profiles with coordinated presets; stack restart on RF changes. ── LXMF chat ── DM tabs from contacts without prior history. Transport badges (RF/TCP/NET). Delivery status with LinkDeliveryManager events; propagation-node badge. ratspeak.chat.v2 reply hashes. Attachments: live send/receive, chunked upload. Voice clips, reactions. Outbox with attempt_count persistence; drain on announce/path/MQTT reconnect. FTS5 search. 4096 B payload limit. ── Peers & identity ── Peers tab with path/probe/favorite/chat/copy hash. reticulumPeerStore + SQLite persistence. peers_updated WS. Identity gen, ratspeak.identity.v2 import, passphrase-encrypted export, multi-identity switcher, announce interval, profile icons from FIELD_ICON_APPEARANCE, blocked contacts. ── Nomad Network ── Sidecar ingests nomadnetwork.node announces; identity_hash for LinkClient::query. Split list + Micron HTML browser (DOMPurify). File downloads via base64 IPC. Transport-aware timeouts (TCP 45 s, RF up to 180 s). 5 s TTL on interfaces GET; 60 s egress cache. ── Topology graph ── Hierarchical: self → interface hubs → peers. Configured interfaces shown as spokes even when idle. buildReticulumViaHashEdges for hub-to-leaf edges. Distant-peer filters. No force-directed fallback. ── Sniffer (all protocols) ── Wireshark-style Pause/Resume with pending count. Batch ingestion per animation frame. Scroll pinning aligned with ChatPanel contract. Fixed virtualizer duplicate keys. Removed dual handleSidecarEvent subscription. ── RNode flasher (Admin) ── nRF52 DFU (SLIP/CRC16), ESP32 esptool-js 0.4.5, EEPROM provision, firmware hash. Unified step UX (flash → provision → set-hash). ESP32 hex parse fix (boot loop). Wi-Fi CMD_WIFI_* → add tcp://host:7633 on Connection tab. ── BLE — triple-protocol coexistence ── BleCoexistenceCoordinator: per-MAC ownership, scan-only mutex, Noble pause/resume without GATT teardown. Same MAC rejected with i18n errors. rns-ble sidecar feature; BLE Peer mesh with seed addresses. ConnectionPanel defers secondary auto-connect; meshtasticEverConfiguredRef gates reconnect. ── Peer graph (Meshtastic/MeshCore) ── buildMeshPeerTopologyGraph with Reticulum-style layout: self → relay hubs → peers. 90-node budget, relay cap at 20, MQTT-only demoted to compact dots. SVG pan/zoom (useSvgPanZoom), hover tooltips, density-aware sizing. Pointer events fixed (no capture-on-mousedown). Default 2 hops. ── i18n audit ── 118 unused keys pruned (2834→2716), CI enforcement. ~304 new keys across all three protocols. Hardcoded-English sweep in Connection, Radio, Modules, Security, Chat, Map, Log, Diagnostics, App, Rooms, Repeaters. meshcoreMessageI18n helper, translateReticulumDiagnosticCause, diagnosticsLabels for routing ports. check-i18n-quality.mjs Reticulum rules. ── Dev/CI tooling ── check:environment (scripts/check-environment.mjs). Flatpak offline pnpm retry. CodeQL pinned refs. Prettier ignores reticulum-sidecar/.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PacketTapEvent/PacketTapDirectionandTransportMessage::SetPacketTapReticulumHandle::register_packet_tapfor embedders (e.g. mesh-client sidecar wire sniffer)Consumer
Colorado-Mesh/mesh-client#596 — Reticulum Stats/Sniffer panel (
wire_packetevents,GET /api/v1/packets)Test plan
cargo test -p rns-transport -p rns-runtimecargo test --features rns-stackwith this branch as sibling