Skip to content

feat: firmware fingerprinting and Meshtastic 2.8/2.8.1 support - #128

Open
mesh-taiwan wants to merge 1 commit into
zenitraM:mainfrom
mesh-taiwan:feat/firmware-fingerprint
Open

mesh-taiwan wants to merge 1 commit into
zenitraM:mainfrom
mesh-taiwan:feat/firmware-fingerprint

Conversation

@mesh-taiwan

@mesh-taiwan mesh-taiwan commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Firmware 2.8 derives node numbers from the public key and signs packets; 2.8.1 lets channels switch to AES-CCM. This keeps Malla working through both and, from the same on-air traits, estimates every node's firmware.

What changes

  • 2.8.1 AEAD channels: AES-CCM (12-byte tag, nonce = packet id + sender, sender/destination as AAD) is tried before AES-CTR in the capture daemon and the web decrypter. Wrong keys fail on the tag, so CTR channels behave as before.
  • 2.8 re-keyed node ids: the node page lists other ids announced with the same MAC ("Same Device", newer/older).
  • Firmware estimate per node, shown on the node page (evidence popover), a /nodes column and the hover card. Traits → lower bound: public_key 2.5+ · relay_node on own packets 2.6+ · is_unmessagable 2.6.8+ · CLIENT_BASE 2.7.8+ · CRC32-derived id or XEdDSA signature 2.8+ · AEAD, PAGING_APP, soil-water telemetry 2.8.1+ · MapReport = exact version.
  • Dashboard card with a Firmware / Hardware toggle: firmware mode is a non-overlapping ladder of proven lower bounds (≥ 2.8.1 … < 2.5) stacking reported vs estimated; hardware mode shows the most common models of nodes heard in the last 7 days, with "Show all" for the full list. Counts and shares are printed on the bars (/api/firmware-distribution, /api/hardware-distribution, 5-minute cache).
  • Capture daemon accumulates the evidence into node_fingerprint (deltas flushed by the main loop once a minute) and backfills history once on first start (fingerprint_backfill_days, default 30, marker in malla_meta). Newer columns are added with ALTER TABLE.
  • meshtastic 2.7.8 → 2.7.11 (protobufs 2.8.0: xeddsa fields, hardware models up to 144). node_info rows stored as UNKNOWN_<n> while the old protobufs did not know the model are renamed at startup.
  • Fixes: get_node_details for nodes without packets (sqlite3.Row.get); channel_index was always NULL.

Review guide

  • fingerprint.py: pure rules + wire-format scanners (no DB). mqtt_capture.py: CCM decrypt, hooks, flush, startup rename. fingerprint_backfill.py: CLI and first-start run. Web: repositories.py, node_routes.py, api_routes.py, three templates. uv.lock: the dependency bump.
  • Version thresholds were checked against the protobuf tag each field first appeared in; the CCM layout against firmware CryptoEngine.cpp. No AEAD traffic exists yet, so CCM is covered by round-trip vectors only.
  • On a 12 GB production DB, all 43 nodes that publish MapReports agree with their fingerprint band; the 30-day backfill (2M packets) ran in ~3.5 min in the background.

Tests

60+ new unit/integration tests (CCM round trip and tag rejection, scanners, every tier, upsert and migration, capture hooks, backfill, hardware rename, routes and both distribution APIs). Full suite green: unit, integration, e2e.

截圖 2026-09-22 凌晨1 38 05

@mesh-taiwan
mesh-taiwan force-pushed the feat/firmware-fingerprint branch 3 times, most recently from c283ab8 to c688f9f Compare September 24, 2026 05:18
- Decrypt AES-CCM (use_aead) channels from firmware 2.8.1, tried before AES-CTR
- Estimate each node's firmware from on-air traits (public key, relay_node,
  is_unmessagable, CLIENT_BASE, CRC32-derived node id, XEdDSA signature,
  AEAD / PAGING_APP / soil-water telemetry); MapReport versions shown verbatim
- Link node ids re-keyed by 2.8 through the MAC in NodeInfo ("Same Device")
- Show it on the node page, /nodes and the hover card; dashboard card with a
  Firmware / Hardware toggle (version ladder or hardware models, "Show all")
- Capture daemon accumulates evidence into node_fingerprint (flushed by the
  main loop) and backfills history once on first start
  (fingerprint_backfill_days, default 30)
- Bump meshtastic to 2.7.11 (protobufs 2.8.0: xeddsa fields, hardware models
  up to 144) and name node_info hardware models stored as UNKNOWN_<n>
- Fix get_node_details for nodes without packets; store MeshPacket.channel
  in channel_index (was always NULL)
@mesh-taiwan
mesh-taiwan force-pushed the feat/firmware-fingerprint branch from c688f9f to c3cf7a9 Compare September 24, 2026 05:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant