Skip to content

v0.30.0+ciris.1 — direct links through NAT (#70), link telemetry (#77)

Latest

Choose a tag to compare

@emooreatx emooreatx released this 08 Oct 00:16

Added

  • Direct-link upgrade (+ciris, leviculum#70): NAT traversal for two nodes
    whose link runs through a transport node. Each learns its public UDP address
    from a facilitator, the two swap addresses over the link, and both punch.
    On success the link moves onto a new point-to-point UDP interface, and
    that interface announces the node's destinations, so paths drop to one hop.
    On failure (symmetric NAT) nothing changes. If the direct interface later
    dies, the link goes back to its previous interface.
    • Wire-compatible with rns-rs's DirectLink protocol: the same channel
      signals (MSGTYPE 0xFE00..=0xFE04), RNSP/STUN probes, punch frames and
      punch token. This is an independent implementation, not a port; rns-rs is
      under the Reticulum License, which AGPL code cannot absorb. Interop was
      verified in all three combinations: rns-rs as relay and facilitator,
      rns-rs accepting a leviculum proposal, and rns-rs proposing to leviculum.
    • Off by default. Config keys probe_port, probe_addr, probe_protocol
      and direct_connect_policy (default reject), or
      ReticulumNodeBuilder::direct_link. API:
      ReticulumNode::propose_direct_link, direct_link_interface, and in
      core NodeCore::{propose_direct_link, take_direct_link_jobs, direct_link_probed, direct_link_punched}. Events: NodeEvent:: {DirectLinkEstablished, DirectLinkFailed, DirectLinkLost}.
    • Only propose to a leviculum or rns-rs peer: a Python RNS peer's channel
      stalls behind the unknown signal.
    • Hardened through five rounds of Codex review on PR #74. Highlights:
      • The link MTU drops to 1400 when the link moves onto the direct
        interface.
      • A one-way failure falls back to the relay, and both ends converge on
        it after an authenticated nudge.
      • Only decrypted traffic over the relay can trigger fallback.
      • Signals pass a full application sink.
      • A link with a transfer under way moves only once the transfer is
        done.
  • Link telemetry (leviculum#77, CIRISServer FSD UNIFIED_TELEMETRY).
    Everything below is on ReticulumNode, and most of it on NodeCore too:
    • link_list(): every link with its caller-visible id, destination,
      role, state, age, idle seconds, measured RTT (None until sampled) and
      interface.
    • link_census(): live links by role, overall and per destination
      (CIRISEdge#819). The initiator keeps a link alive with its keepalives,
      so a rising initiator count names a node that does not close what it
      dialled.
    • link_lifecycle(): established by role, closed by LinkCloseReason,
      handshake failures by reason, and requests the application refused.
      established - closed_total equals the live census.
    • link_count_check(), plus an event-loop alarm. If the completion
      mirror and the core disagree on the established-link count for more
      than 30 s, a LINK_MIRROR_DIVERGED event is raised, once per episode.
    • heap_census(): the core's accounted heap by component, on std hosts.
    • publish_metrics() records 24 catalogued metrics
      (leviculum_std::telemetry::METRIC_CATALOG) through the metrics crate
      facade. There is no exporter dependency; the host installs the recorder.
      Counters are process totals, so several nodes sum and a late recorder
      still reads full totals. Every label value is a bounded enumeration.
      event_catalog_completeness now also checks metric names and label
      keys against the catalogue.
  • A test pinning the invariant CIRISEdge relies on: a resource whose link
    closes during off-lock assembly fails exactly once, as LinkClosed,
    before the link's LinkClosed, and its late result completes nothing.

Changed

  • reject_link refuses only a pending inbound request. Any other link is
    closed the way close_link closes it, with a close packet and
    LinkClosed. Before, it dropped the link silently, so the completion
    mirror and the counters went on treating it as alive.

Consumer notes

  • Additions only; no existing public signature changed. NodeEvent (non-
    exhaustive) gains DirectLinkEstablished, DirectLinkFailed and
    DirectLinkLost. leviculum_std::Error gains DirectLink.
  • New dependency in leviculum-std: metrics 0.24, with default features
    off. THIRD-PARTY-NOTICES is regenerated.
  • Direct links are inert unless configured. With the default policy
    (reject) and no facilitator, the node never proposes, refuses every
    request, and the event loop never looks for direct-link work.