Files
firmware/test/support
TomandBen Meadors 20f7ab1be9 Relay a PKI unicast with a known party in LOCAL_ONLY and KNOWN_ONLY (#11898)
* fix(router): relay a PKI unicast with a known party in LOCAL_ONLY and KNOWN_ONLY

A frame the relay cannot decrypt takes the OPAQUE_RELAY_ONLY path in
Router::perhapsHandleReceived() and returns before handleReceived(), so it never
reaches a module. The rebroadcast_mode rule for opaque traffic is therefore the
IS_ONE_OF list in relayOpaquePacket(), and LOCAL_ONLY and KNOWN_ONLY were not on
it: a node in either mode dropped every opaque frame, including a PKI unicast
with a party it knows. The gate in RoutingModule::handleReceivedProtobuf() that
used to allow exactly that is unreachable for these packets and no longer
decides anything.

Add both modes to the list, with the identity rule the unreachable gate carried:
a PKI-shaped unicast (channel 0, not broadcast) with `from` or `to` known to us.
An unreadable broadcast and a unicast between two strangers stay dropped in
these modes, which is what the proto documents - they ignore foreign meshes.

This is not only direct messages. Remote administration and key verification are
PKI unicasts too, and a KNOWN_ONLY relay was black-holing those between two
other nodes just the same.

CORE_PORTNUMS_ONLY reached this list the same way in #11843; this is the
remaining pair.

* test(rebroadcast_mode): pin the relay decision per mode, in both directions

What this node carries for other nodes, per DeviceConfig.rebroadcast_mode, for
packets it can read and packets it cannot. The harness pushes a real PKI frame
through Router::perhapsHandleReceived() and counts what reaches the radio.

Both directions are load-bearing, and each is guarded by cases the other leaves
green. Measured by rebuilding the firmware three ways:

  - as shipped: 9/9 pass.
  - with the two modes taken back out of relayOpaquePacket(): the known-party
    and remote-admin cases fail, the stranger and foreign-mesh cases still pass.
  - with the modes listed but the identity qualifier deleted: the stranger and
    foreign-mesh cases fail, the known-party cases still pass.

So a revert and an over-broadening each fail their own tests, and neither can be
satisfied by breaking the other.

The suite and its harness come from the opaque-packet-handling branch and
compile against develop unmodified. Two assertions were dropped because they
pin behaviour this branch does not add: delivery of unreadable frames to the
phone, and a queued copy of our own suppressing the originator's repeat, which
needs relayOpaquePacket() to consult the TX queue.

* fix(test): guard the harness include, drop a comment its test outlived

Two review findings on the imported suite.

The harness builds real PKI frames through CryptoEngine entry points a
MESHTASTIC_EXCLUDE_PKI build does not declare, but it was included above the
guard, so the empty-suite branch that exists for those builds could not compile.
Move the include inside the guard and pull the base includes the stub branch
needs above it.

The phone-delivery case was dropped when the suite came across - this branch
does not deliver unreadable frames to the phone - but its comment stayed behind
and now described the test below it, which is about the signature policy.

* test(rebroadcast_mode): make the from-known and channel-0 operands load-bearing

The qualifier has three operands, and the suite only exercised one of them.

Every existing case that a known party carries has a known DESTINATION: the
remote-admin case marks both parties, the known-destination case marks the
target. Rewriting the identity test to consult p->to alone passed all nine. And
the only non-PKI-shaped frame in the suite was a broadcast, which
!isBroadcast(p->to) rejects before p->channel is ever read, so deleting the
channel gate passed all nine too.

Add the two cases that close it: a known SOURCE with a destination we have never
heard of, which must relay in both modes, and a known party on a channel hash we
do not hold, which must not - that is someone else's channel traffic, addressed,
not PKI.

Measured both ways. With the from operand and the channel gate removed from
relayOpaquePacket(), the two new cases fail and the other nine pass; with the
shipping code, 11/11.

Raised by CodeRabbit on #11898.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-09-20 10:29:48 +00:00
..