Skip to content
Esporta

Transport

Role

pkg/transport is the routing engine. It learns paths from signed announces, forwards packets across interfaces, maintains link table state, and delivers data packets to registered destinations.

Transport sits between interfaces and application destinations. Every enabled interface registers with Transport.RegisterInterface, which sets a callback from inbound frames to HandlePacket.

Inbound packets are unpacked in pkg/packet. Hop counts >= PATHFINDER_M (128) are rejected at unpack time (RNS 1.3.8). Transport also drops announces and relayed packets that would exceed MaxHops after increment.

Path table

The path table maps a 16-byte destination hash to:

  • Next-hop interface name
  • Hop count and timestamps
  • Transport ID for multi-hop type-2 headers
  • Interface-specific metadata

Paths are learned from:

  • Signed announces received on interfaces
  • Path response packets
  • Explicit path requests from applications or the control API

Path selection

When multiple paths exist, transport uses random-blob selection aligned with Python 1.3.4 deduplication behavior (pkg/transport/path_selection.go).

Path requests

Applications call RequestPath on transport or use destination helpers. Ingress and egress controls (pkg/rate, pkg/transport/ingress.go) limit announce and path-request rates per interface configuration.

Unknown-path discovery (rebroadcasting a path request when no path is known) runs only when the receiving interface is in a discover mode (access_point, gateway, roaming, internal) or has recursive_prs = yes (RNS 1.3.6+).

Announce rebroadcast also applies interface mode filters (AP block, roaming/boundary/internal next-hop rules). See Interfaces.

Persistence

By default the path table can persist to storage/destination_table as msgpack with a layout compatible with Python. Set in_memory_path_table = yes to keep paths in RAM only.

Known destinations persist under storage/known_destinations/. Set in_memory_known_destinations = yes for RAM-only mode.

Set in_memory_storage = yes for fully ephemeral stack state (paths, known destinations, transport identity, blackhole, and split-resource staging). Optional soft_memory_limit and max_in_memory_* keys bound RAM under that mode.

Packet handling

Inbound packets enter HandlePacket and branch on packet type:

HandlePacket
  |
  +-- Announce  -> handleAnnouncePacket
  |                 update path table, invoke announce handlers
  |
  +-- Link      -> handleLinkPacket
  |                 link setup, identify, keepalive
  |
  +-- Proof     -> handleProofPacket
  |
  +-- Data      -> handleTransportPacket
                    |
                    +-- ContextPathResponse -> handlePathResponse
                    +-- forwardTransportPacket (type-2 relay)
                    +-- forwardLinkData
                    +-- deliver to Destination.Receive

Header type 2 relay

When transport mode is enabled and the local node acts as a relay, data packets may be rewrapped with header type 2 if the transport ID in the path matches. This matches Python transport relay semantics.

Announce deduplication

If a destination is already present in the path table, duplicate announces may be dropped per Python 1.3.4 behavior.

Links at the transport layer

Transport maintains a link table for active sessions. Link packets are routed to the correct pkg/link instance. Incoming link requests are dispatched to link.HandleIncomingLinkRequest (incoming link requests use link.HandleIncomingLinkRequest).

Blackhole interaction

When pkg/blackhole has an entry for an identity hash, announces from that identity are dropped and links are torn down at LINKIDENTIFY. Blackhole federation (publish_blackhole, remote sources) is not implemented. See Compatibility.

Transport identity

When enable_transport = yes, transport may use a dedicated transport identity stored at storage/transport_identity. This identity participates in transport-mode relay and proofs as defined by the protocol.

Registration API

Typical embedder sequence:

tr := transport.NewTransport(cfg)
tr.Start()

iface, err := interfaces.NewFromConfigWithContext(ctx, name, ifaceCfg)
tr.RegisterInterface(name, iface)
iface.Start()

RegisterInterface binds the interface packet callback to HandlePacket.

Outbound send path:

err := tr.SendPacket(pkt)

SendPacket looks up the path, may rewrap for relay, serializes, and calls Interface.Send on the chosen interface.

Rate limiting and ingress control

Per-interface ingress_control and announce_rate_* settings map to token buckets in pkg/rate. This mirrors Python 1.2.5 path-request and announce controls.

Probes

Set respond_to_probes = yes (or allow_probes) to register rnstransport.probe with prove-all so reticulum-go probe can measure RTT against this node.

Debugging

Raise loglevel in config. Transport logs at debug levels 5 and above include path updates and forwarding decisions via pkg/debug.

Testing

Test area Location
Wire parity tests/crossref (path requests, announces, relay)
Live relay tests/interop/transport_relay_live_test.go (RUN_LIVE_INTEROP=1)
Live paths tests/interop/transport_path_live_test.go
Property tests pkg/transport/*_pbt_test.go
Race tests pkg/transport/*_race_test.go

Related documents

R
Reticulum-Go

A Go implementation of the Reticulum Network Stack. Building the future of resilient, sovereign communications.

Implementation License: Apache-2.0

Follow Development

Links

Quad4 Software

Backed by Quad4 Software. Building privacy-first, secure, efficient software.

quad4.io
© 2026 Quad4 Software. All rights reserved.
Deployed using Coolify