Skip to content

fix(region): code-0 floods obey denyf * and flood.max.unscoped - #22

Merged
Elektr0Vodka merged 1 commit into
dmc-devfrom
fix/dmc-dev-zero-scope-unscoped
Oct 19, 2026
Merged

Elektr0Vodka merged 1 commit into
dmc-devfrom
fix/dmc-dev-zero-scope-unscoped

Conversation

@Elektr0Vodka

Copy link
Copy Markdown

Problem

Upstream meshcore-dev#3568 (in v1.18) made RegionMap::findMatch() return the wildcard for a TRANSPORT_FLOOD whose transport_codes[0] is 0 ("treat code 0 the same as un-scoped"). It does this without checking the wildcard's flags. On top of that, isFloodHopLimitExceeded() only applies flood.max.unscoped to ROUTE_TYPE_FLOOD.

So a code-0 packet:

  • passes region denyf *
  • skips flood.max.unscoped (only flood.max 64 / flood.max.advert apply)
  • ignores our dc.gate runtime gate on *

Stock clients never send code 0, but any modified client can. The gap is still present on upstream main and dev.

Fix

  • findMatch(): code 0 returns the wildcard only when wildcard.effectiveFlags() (config + runtime gate) allows the mask, otherwise NULL. That's the same rule onRecvPacket() already applies to plain unscoped floods.
  • RoutingPolicy.h: new isUnscopedFlood() (FLOOD, or TRANSPORT_FLOOD with code 0), used for the flood.max.unscoped check.

Scoped traffic is unchanged: a real code still matches its region even while * is denied. Replies to an allowed code-0 request still go back unscoped (chooseReplyScope).

Tests

  • test_region_gating: code 0 with * allowed / denied (denyf *) / held by dc.gate, code 0 with a codes[1] hint, and a named region still matching while * is denied. The three deny cases failed before the fix.
  • test_routing_policy: isUnscopedFlood() cases, and code-0 hop limits at 0 and N. makeFlood() now sets an explicit transport code for scoped packets, because Packet() leaves transport_codes uninitialised.
  • native 252/252, native_region_gating 25/25.
  • Builds: Heltec_v3_repeater, Heltec_v3_room_server, RAK_4631_repeater.

Follow-ups

  • Propagate to dmc-observer-dev / packetlog after merge (same gap there).
  • Upstream PR to meshcore-dev/MeshCore dev (text drafted; upstream has no rt_flags, so it uses wildcard.flags).

🤖 Generated with Claude Code

Upstream meshcore-dev#3568 made RegionMap::findMatch() return the wildcard for a
TRANSPORT_FLOOD with transport code 0, without checking the wildcard's
flags. isFloodHopLimitExceeded() only applied flood.max.unscoped to
ROUTE_TYPE_FLOOD. A code-0 packet therefore passed 'region denyf *',
skipped flood.max.unscoped, and ignored the duty-cycle gate on '*'.

- findMatch(): code 0 returns the wildcard only when its effective
  flags (config + runtime gate) allow the mask, otherwise NULL.
- RoutingPolicy: new isUnscopedFlood() (FLOOD, or TRANSPORT_FLOOD with
  code 0), used for the flood.max.unscoped check.

Tests: findMatch code-0 cases in test_region_gating; isUnscopedFlood and
code-0 hop limits in test_routing_policy. makeFlood() now sets an
explicit transport code, since Packet() leaves transport_codes
uninitialised.
@Elektr0Vodka
Elektr0Vodka merged commit 6117cd2 into dmc-dev Oct 19, 2026
1 check passed
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