Skip to content

Pt97 compliance, Add strict gatekeeper mode for Meshtastic/MeshCore ingress#17

Open
mathisono wants to merge 25 commits into
kn6plv:mainfrom
mathisono:pt97-compliance
Open

Pt97 compliance, Add strict gatekeeper mode for Meshtastic/MeshCore ingress#17
mathisono wants to merge 25 commits into
kn6plv:mainfrom
mathisono:pt97-compliance

Conversation

@mathisono
Copy link
Copy Markdown

Summary

This PR adds an optional Strict Gatekeeper mode for Raven bridge deployments that forward Meshtastic or MeshCore text traffic into AREDN.

The goal is to make the bridge fail closed for common amateur-radio compliance risks when crossing from an unlicensed mesh into an AREDN / amateur-radio network.

What changed

  • Adds a new gatekeeper.uc policy module.
  • Adds strict_gatekeeper configuration support:
{
  "strict_gatekeeper": {
    "enabled": true,
    "gateway_callsign": "W6XYZ",
    "allowed_callsigns": ["KN6PLV", "KJ6DZB"]
  }
}
  • Validates sender identity by extracting a US-style callsign token from node names.
  • Supports an optional allowed_callsigns whitelist.
  • Drops encrypted Meshtastic packets before the legacy decrypt path is reached.
  • Drops non-text Meshtastic/MeshCore bridge ingress in strict mode.
  • Rewrites accepted bridged text to originate from the gateway node instead of spoofing the remote Meshtastic/MeshCore sender.
  • Prefixes bridged text as:
[SENDER via GATEWAY] message

For example:

[KN6PLV via W6XYZ] Hello
  • Adds a router-level defense-in-depth filter so future transport changes do not accidentally enqueue non-compliant bridge ingress.
  • Adds STRICT_GATEKEEPER.md documenting configuration, behavior, and operational caveats.
  • Links the new guide from the README.

Rationale

Meshtastic and MeshCore are useful companion meshes, but AREDN runs in a licensed amateur-radio environment where cleartext operation, station identification, and operator control matter.

The previous behavior allowed bridge traffic to be forwarded too openly. This PR introduces an opt-in mode that:

  1. rejects encrypted Meshtastic ingress before decryption;
  2. requires the apparent sender to match a callsign-shaped identity and optional whitelist;
  3. injects the final AREDN message as the gateway station, with the remote operator identified in the message body.

This preserves existing non-strict behavior by default while providing a safer operating mode for regulated deployments.

Notes and caveats

Strict Gatekeeper mode is not cryptographic identity proof. Meshtastic and MeshCore names are user-controlled, so a node can be renamed to look like a valid callsign. For real deployments, operators should use allowed_callsigns, and a later hardening step should bind allowed operators to stable Meshtastic node IDs or MeshCore public keys.

The callsign validator intentionally matches a simple US amateur callsign form: one or two letters, one numeral, and one to three letters. This will reject international callsigns or unusual/special-event formats that do not contain an extractable US-style token.

Dropped packet logging uses the existing DEBUG0 and DEBUG1 channels, so headless OpenWrt deployments should confirm service/logd capture before relying on logs for troubleshooting.

Testing

  • Not yet tested on live RF hardware in this PR.

  • Code was reviewed for ingress chokepoints:

    • Meshtastic encrypted packets are rejected in meshtastic.uc before decrypt branches run.
    • Meshtastic/MeshCore ingress is filtered before router queue admission.
    • Accepted text is rewritten to use the gateway node identity.

Follow-up work

MeshCore direct-message handling currently still performs protocol-level decryption inside meshcore.uc before the router-level strict filter sees the decoded text. The router filter prevents non-text or non-rewritten MeshCore ingress from entering the queue, but the strictest future improvement would be to add a MeshCore decoder-level gate similar to the Meshtastic encrypted-packet hard stop.

1. Add exponential backoff for APRS backend reconnection (5s base,
   5min cap) to avoid hammering unreachable servers every poll cycle.

2. Fix recv() to buffer all messages from a single read instead of
   returning only the first match. Remaining messages are drained via
   tick() -> router.queue() on the next cycle, and recv() checks the
   pending buffer before reading more data from the socket.

3. Separate kiss_rxbuf from rxbuf so KISS unframing and TNC2 line
   buffering never collide.

4. Send APRS ACK for every inbound message that carries a message-id,
   so the remote station knows Raven received the packet.
mathisono pushed a commit to mathisono/Raven that referenced this pull request Jun 3, 2026
- Add strict gatekeeper mode for Meshtastic/MeshCore ingress (Part 97 compliance)
- Add APRS bridge with APRS-IS, KISS TCP, and TCP text backends
- APRS hardening: reconnect backoff, buffered recv, inbound ACK
@aanon4 aanon4 added the AI used label Jun 3, 2026
…stic

ucode's module resolver rejects cycles in the import graph. The chain
config→router→meshtastic→gatekeeper, with config also importing
gatekeeper directly, triggers a circular dependency error.

Break the cycle by:
- Removing 'import gatekeeper' from both router.uc and meshtastic.uc
- Adding router.setGatekeeper() to inject the reference at setup time
- Passing gatekeeper via config._gatekeeper for meshtastic.uc
- Using optional chaining (gatekeeper?.isEnabled()) so both modules
  work safely before the reference is injected
builder_bob added 6 commits June 2, 2026 19:50
When the APRS channel is selected, the input placeholder shows
'@callsign message  or  #group message ...' so users know the
direct-message and group syntax without reading docs.
- aprs.process() was empty, so outbound messages from UI never reached
  APRS-IS. Now calls send() for locally-originated messages.
- Regex for parsing message IDs didn't handle APRS 1.1 reply-ack
  trailing '}', causing {01} to appear in message text and ACKs
  not being sent back (Xastir kept retransmitting).
…eed channel

- Inbound messages from callsigns with a DM channel (e.g. kj6dzb-4 og==)
  now route to that DM channel instead of always going to the group feed.
- Group members always route to the main APRS feed channel.
- Outbound from DM channels auto-routes to the callsign in the channel
  name, stripping redundant @callsign prefix if present.
- Default feed channel renamed to APRS-IS-Feed (no spaces in namekey).
- Feed channel is auto-registered at setup even if not in config.
- Channel key extracted once at setup for efficient DM matching.
…nly, wire up gatekeeper ref in meshcore

- meshcore.uc: accept gatekeeper reference from config, add early-drop comment for encrypted packets
- router.uc: when gatekeeper strict, only bridge text_message outbound to MeshCore and Meshtastic
- Remove old r12 package artifacts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants