Skip to content

[transport] No port hopping; the static listen-port set is still an enumerable blocking target (time-synced KDF schedule, no handshake) #146

Description

@jamiesun

Context Boundary

Expectation vs. Reality

Expected: to resist port-based blocking, the active port(s) change over time on a schedule both ends derive independently — so a blocklist of "the subnetra ports" goes stale.

Actual: after the multi-port PR a node binds an explicit, static set (default [18020, 18023, 18026]). That already reduces single-port blast radius and drops the 51820 fingerprint, but the set is fixed for the process lifetime — once enumerated it is a stable target. There is no port hopping.

Implementation Path (design sketch — static-config only, no handshake)

  1. Time-synced port schedule (no negotiation). Derive the active port(s) for slot t from a per-link secret already shared, e.g. port = base + (Blake2b(link_key, floor(now/slot)) mod span) over a configured candidate space — both ends compute it from the wall clock + link_key, so there is no on-wire exchange (iron law [test] Enable the gated multi-point + relay e2e netns test #8). All inputs are static config (hop_slot_secs, candidate range/list, enable flag).
  2. Receiver coverage during slot edges. To tolerate clock skew, bind the current AND adjacent slot's port(s) (a small window), reusing the multi-port socket set already added here. Egress targets the peer's current-slot port; the listen side already returns out the socket a peer was last heard on.
  3. Clock dependency. Hopping needs loose time sync (NTP/RTC) — same operational note as the epoch/clock-backward constraint (iron law [test] Enable the gated multi-point + relay e2e netns test #8 consequence (b)); document it.
  4. Interaction with NAT. A NATed spoke's source port is NAT-mapped anyway; hopping primarily helps the hub's reachable port and spoke→hub destination. Scope carefully (hub-side hop most valuable).
  5. Counters/observability: udp_port_hop transitions; subnetra status shows the current slot's port(s).

Constraints / Non-Goals

Acceptance Criteria

  • A written design (KDF, slot window, clock-skew tolerance, NAT analysis) reviewed against iron law [test] Enable the gated multi-point + relay e2e netns test #8.
  • Two nodes with hopping enabled stay connected across ≥3 slot transitions with no manual reconfig and no on-wire schedule exchange; zig build + zig build test green; PROTOCOL.md updated.
  • Hopping OFF leaves today's static listen_ports behaviour byte-identical.

Blast Radius

  • Affected paths: deployments facing active port-based blocking/enumeration.
  • Severity rationale: medium — meaningful censorship-resistance upgrade, but adds clock-sync coupling and complexity; a small-scale-network posture may prefer the simpler static set.
  • Priority: P2 (depends on multi-port listen, which this builds on).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: P2Depends on earlier work / verificationsecuritySecurity hardening or vulnerability

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions