Commit Graph

19 Commits

Author SHA1 Message Date
agessaman b5a327b925 fix(router): defer direct payload handling 2026-07-14 21:08:42 -07:00
agessaman 612a4c3f0e fix(companion): route group and raw data like MeshCore 2026-07-14 20:40:13 -07:00
agessaman 059065ce9c fix(router): never forward control packets to the engine
MeshCore never relays control packets: the direct high-bit discovery
subset is explicitly released and any other control payload hits the
switch default that does not flood-route unknown types. Mark control
packets do-not-retransmit unconditionally instead of only when discovery
is enabled, so a repeater with discovery disabled no longer forwards
control/discovery traffic.
2026-07-13 20:40:22 -07:00
agessaman 62ad7424c2 fix(router): consume PATH and RESPONSE only after MAC authentication
Extend the authenticated-ownership model to the PATH and RESPONSE
routing branches so a packet is consumed (do-not-retransmit) only when
a local identity MAC-verifies it. Prefix-only collisions and forged
traffic stay eligible for the forwarding engine.

- PathHelper marks do-not-retransmit and reports authenticated only
  after a successful MAC decrypt with a valid path envelope; invalid or
  truncated envelopes remain forwardable.
- PacketRouter aggregates authenticated results across the path helper
  and companion bridges for PATH and RESPONSE, skipping the engine only
  on authenticated ownership while preserving empty-path DIRECT release
  hygiene.
2026-07-13 19:54:59 -07:00
agessaman 8875177088 fix(router): consume packets only on authenticated local handling (#353)
Route login, text, and protocol-request packets through a single
_consume_via_local_candidates fan-out that offers each one to every local
candidate sharing the one-byte destination hash — the companion bridge and the
room-server/repeater identity — and consumes it only when one MAC-verifies it.
A prefix collision with a remote node (or a forged packet) is left for the
forwarding engine instead of being swallowed.

- gate processed_by_injection on the core HandlerResult.authenticated
- protocol-request now forwards on collision instead of always marking handled
- add real-crypto integration tests (text, room-server login, protocol-request)
  and router fan-out tests covering companion + room-server collisions
2026-07-13 14:46:56 -07:00
agessaman 4a055be8df fix(router): try both companion and server on colliding dest hash
On-air dest hashes are one byte, so a companion and a room-server (or
repeater) identity can share one. The login and text dispatch used
`if dest_hash in companion_bridges: ... elif login_helper/text_helper`,
so a companion silently shadowed a same-hash room server: its login
never reached the room-server handler and failed with Invalid HMAC
(e.g. Lake Stevens pubkey f55d.. / hash 0xf5 colliding with a companion).

Offer the packet to both handlers when both are registered at the hash;
decryption disambiguates — the key owner replies, the other fails HMAC
and no-ops. Non-colliding paths are unchanged. Applied to both the
LoginServerHandler and TextMessageHandler branches.

Adds regression tests covering collision (both invoked), companion-only
(server helper skipped), and server-without-companion for each path.
2026-07-07 14:51:59 -07:00
agessaman 954150b2d8 merge: reconcile companion cleanup with fix-general-tidy
Merge the maintainer's fix-general-tidy branch (neighbor discovery,
keygen, API endpoints, web-asset rebuild, HTTP server config/control
commands, and an independent #286 room-server push/ACK/guest fix) into
the companion cleanup branch.

Both branches fixed #286 in parallel with byte-identical push-ACK CRC
logic. In the six overlapping files the maintainer's implementation is
kept (ACL replay-detection/session helpers, encoded path-len with legacy
fallback, expected_crc/ack_timeout_s injector API, dispatcher ACK
helpers); this branch's unique companion work is preserved on top
(sender_prefix persistence + migration, boot-state hardening /
CompanionStateLoadError, MessageQueue.max_size, older-core fallbacks).

Conflict resolution took the maintainer's side across the overlap, then
fixed two integration seams the merge introduced and updated this
branch's tests to the maintainer's API:
- room_server: timeout used undefined `hops`; aligned to `path_len`.
- packet_router: PATH helper was invoked twice (maintainer's
  unconditional call plus this branch's conditional local-identity
  call); dropped the now-redundant conditional block.

Pin openhop_core to @dev (was @feature/publish-workflow-message-handling)
so this can merge to the repeater's dev; core dev carries the required
sender_prefix and PathUtils.is_valid_path_len APIs.

Full suite green (1040 passed) against openhop_core dev and
refactor/companion-housekeeping; ruff clean.
2026-07-07 12:56:43 -07:00
agessaman b2e45c2038 fix: resolve room-server push ACKs through the dispatcher
Room server pushes waited on dispatcher.wait_for_ack, but nothing in the
repeater could ever resolve it, so every push timed out and re-pushed on
the backoff schedule (issue #286's duplicate floods — worst for virtual
companions on the same instance, whose ACKs never even cross the air):

- no core AckHandler is registered (all RX lands in the router fallback),
  so received ACK CRCs were never fed to dispatcher ACK matching
- inject_packet waited on packet.get_crc(), a packet-hash CRC that no ACK
  sender produces; the crypto CRC only the room server knows was ignored
- PATH returns (how a flood-received DM is ACKed) were decrypted by
  PathHelper, but it read the encoded path_len wire byte as a raw count —
  an empty 3-byte-hash path (0x80) parsed as a 128-byte truncated
  payload — and the router's PATH branch never ran PathHelper for
  room/repeater destinations when any companion bridge existed

Fixes:
- router ACK branch feeds discrete ACK CRCs (RF and locally injected) to
  dispatcher._register_ack_received
- PATH packets addressed to a local server identity are processed by
  PathHelper regardless of companion bridges; PathHelper decodes the
  encoded path_len via PathUtils, keeps the encoded byte in out_path_len,
  and registers the embedded ACK via ack_received_fn
- inject_packet accepts expected_ack_crc/ack_timeout; the room server
  passes its crypto CRC and a hop-count-based timeout (the encoded byte
  would have produced a ~4-minute direct-push wait)

Verified live on a real mesh: push to a same-instance virtual companion
resolves via the PATH-embedded ACK (encoded path_len 0x80) and push to a
firmware client resolves via the discrete RF ACK, no re-push loops.

Fixes #286
Fixes #341
2026-07-07 11:17:54 -07:00
Lloyd 823308aa3f fix: update drop reason handling in PacketRouter and RepeaterHandler 2026-06-29 15:48:19 +01:00
Lloyd 2b67dea96b refactor:rename-project-to-openhop 2026-06-24 23:27:49 +01:00
Rightup 14b4804c26 feat: Enhance logging system and introduce policy management endpoints
- Updated LogBuffer to support log entry IDs, enhanced log entry structure with additional metadata, and implemented subscriber management for real-time log streaming.
- Added OpenAPI specifications for new endpoints related to policy management, including retrieval, updating, validation, and group management for network policies.
- Implemented comprehensive tests for new policy endpoints, ensuring correct behavior for creating, updating, validating, and deleting policy groups and entries.
- Introduced policy evaluation tests to validate the functionality of the PolicyEngine, including various scenarios for action decisions based on defined rules.
- Enhanced packet routing tests to ensure proper handling of policy decisions in packet processing.
2026-06-04 15:53:17 +01:00
Lloyd cd7058be99 fix: update packet router debugs for less noise and policy prep for advanced filters works 2026-06-02 12:18:17 +01:00
agessaman e24cdca055 feat(companion): echo injected TX to companion clients as raw RX (0x88)
Push locally-injected TX packets to connected companion frame server
clients as PUSH_CODE_LOG_RX_DATA (0x88) with snr=0/rssi=0, so apps that
decrypt locally from raw RX (e.g. RemoteTerm) see companion-originated
channel traffic. The originating companion is excluded so a node never
hears its own transmission, matching physical firmware behavior.
inject_packet now takes an origin_hash (threaded per-companion via the
packet_injector partial); _on_raw_rx_for_companions gains exclude_hash
to skip that companion's frame server. OTA RX is unaffected.
2026-06-01 17:05:38 -07:00
agessaman 5a9e1c87cc Merge branch 'fix/companion-message-send' into feat/pre-1160-compatibility-sendfix
Bring in companion transmission handling improvements from RepeaterHandler.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 21:42:26 -07:00
Lloyd 45a44eb47b Refactor test cases and base code for consistency and readability
- Updated byte representations in tests to use lowercase hex format for consistency.
- Reformatted code for better readability, including line breaks and indentation adjustments.
- Consolidated multiple lines into single lines where appropriate to enhance clarity.
- Ensured that all test cases maintain consistent formatting and style across the test suite.
2026-05-27 20:15:10 +01:00
Lloyd 37ee0e892a Add more unit tests for handler helpers, identity manager, CLI, key generation, and main functionality
- Introduced tests for TraceHelper and DiscoveryHelper to validate packet forwarding and discovery request handling.
- Implemented tests for LoginHelper to ensure identity registration and login packet processing.
- Added tests for IdentityManager to cover identity registration, lookup, and filtering.
- Created tests for MeshCLI to verify command handling, configuration setting, and error paths.
2026-05-26 13:01:38 +01:00
agessaman 2d5353ad7d fix(companion): improve transmission handling in RepeaterHandler
- Updated the __call__ method to return a boolean indicating transmission success.
- Adjusted handling of transmission failures to increment dropped_count appropriately.
- Enhanced logging for transmission failures in PacketRouter to ensure visibility of issues.
- Added tests to verify correct behavior during transmission exceptions and failures.
2026-05-16 17:32:15 -07:00
Lloyd e0dd91b91e Skip inbound trace processing for locally injected TRACE packets 2026-04-24 10:04:01 +01:00
TJ Downes 7d1aa57321 fix(router): drain in-flight tasks on shutdown; add drop counter; add tests
Addresses PR 191 reviewer feedback:

1. Shutdown drain
   stop() now waits up to 5 s for in-flight _route_packet tasks to finish,
   then cancels any that remain.  Previously only the queue-consumer loop was
   cancelled; created tasks were abandoned with no guarantee they completed.

   Mechanism: _route_tasks set tracks live tasks (added on create, discarded
   in the done-callback).  stop() takes a snapshot and calls asyncio.wait()
   with timeout=5.0, then cancels the still-pending subset.

2. Drop counter
   _cap_drop_count increments each time a packet is dropped at the cap.
   The running total is included in every WARNING log line and also printed
   at shutdown so operators can tell at a glance whether the safety valve is
   actually firing in production.

3. Tests (tests/test_packet_router.py)
   test_cap_drops_packets_when_full     — cap=3, send 8 → 5 drops, 3 in-flight
   test_cap_drop_count_increments       — count increments by 1 per drop
   test_cap_drop_count_zero_...         — count stays 0 when cap never reached
   test_stop_waits_for_in_flight_tasks  — slow task (0.2 s) completes, not cancelled
   test_stop_cancels_tasks_...timeout   — hanging task cancelled after timeout
   test_route_tasks_set_cleaned_up      — set empty after all tasks finish
   test_counter_matches_set_size        — _in_flight == len(_route_tasks) at cap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 05:46:49 -07:00