config

package
v0.1.59999 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package ssu2 provides SSU2-specific implementations for the Noise Protocol Framework supporting I2P's SSU2 transport protocol with UDP-based connections and NAT traversal.

Index

Constants

View Source
const (
	// DefaultHandshakeTimeout is the spec-defined handshake timeout of 15 seconds.
	// Per ssu2.rst: "Handshake timeout: 15 seconds"
	DefaultHandshakeTimeout = 15 * time.Second
)

Default timeout values per SSU2 specification (ssu2.rst)

Variables

This section is empty.

Functions

func DefaultRouterInfoValidator

func DefaultRouterInfoValidator(routerInfo, authenticatedStaticKey []byte) error

DefaultRouterInfoValidator validates that the Noise-authenticated static key matches the "s" option in an SSU2 address within the RouterInfo.

It parses the RouterInfo binary payload, locates SSU2 router addresses, and compares the static key from the "s" option against the Noise-authenticated static key using constant-time comparison.

Per SSU2 spec §SessionConfirmed Notes, the responder must verify that the static key authenticated by the Noise handshake corresponds to the key published in the peer's RouterInfo.

func GenerateConnectionID

func GenerateConnectionID() (uint64, error)

GenerateConnectionID generates a cryptographically secure random connection ID. The ID is guaranteed to be non-zero (zero is reserved for handshake). This is a convenience function for creating SSU2 addresses.

Types

type SSU2Addr

type SSU2Addr struct {
	// contains filtered or unexported fields
}

SSU2Addr implements net.Addr for SSU2 transport connections. It provides I2P-specific addressing information including router identity, connection ID, and optional introducer support for NAT traversal.

func NewMockSSU2Addr

func NewMockSSU2Addr(connID uint64) *SSU2Addr

NewMockSSU2Addr creates a minimal SSU2Addr with only the connectionID set. It is intended for use in tests that need a placeholder address.

func NewSSU2Addr

func NewSSU2Addr(underlying net.Addr, routerHash data.Hash, connID uint64, role string) (*SSU2Addr, error)

NewSSU2Addr creates a new SSU2Addr with the specified UDP address, router hash, connection ID, and role. routerHash is the I2P router identity hash. connID should be a cryptographically secure random 8-byte value (use GenerateConnectionID). role should be either "initiator" or "responder".

func (*SSU2Addr) ConnectionID

func (sa *SSU2Addr) ConnectionID() uint64

ConnectionID returns the SSU2 connection identifier.

func (*SSU2Addr) DestinationHash

func (sa *SSU2Addr) DestinationHash() *data.Hash

DestinationHash returns the destination hash, or nil for router-to-router connections.

func (*SSU2Addr) IntroducerAddr

func (sa *SSU2Addr) IntroducerAddr() net.Addr

IntroducerAddr returns the introducer address, or nil if no introducer is used.

func (*SSU2Addr) IsDirectConnection

func (sa *SSU2Addr) IsDirectConnection() bool

IsDirectConnection returns true if this is a direct connection (no introducer).

func (*SSU2Addr) IsIntroducedConnection

func (sa *SSU2Addr) IsIntroducedConnection() bool

IsIntroducedConnection returns true if this connection uses an introducer for NAT traversal.

func (*SSU2Addr) IsRouterToRouter

func (sa *SSU2Addr) IsRouterToRouter() bool

IsRouterToRouter returns true if this is a router-to-router connection (no destination hash).

func (*SSU2Addr) IsTunnelConnection

func (sa *SSU2Addr) IsTunnelConnection() bool

IsTunnelConnection returns true if this is a tunnel connection (has destination hash).

func (*SSU2Addr) Network

func (sa *SSU2Addr) Network() string

Network returns "ssu2" to identify this as an SSU2 transport address. This implements the net.Addr interface requirement.

func (*SSU2Addr) Role

func (sa *SSU2Addr) Role() string

Role returns the connection role ("initiator" or "responder").

func (*SSU2Addr) RouterHash

func (sa *SSU2Addr) RouterHash() data.Hash

RouterHash returns the router identity hash.

func (*SSU2Addr) String

func (sa *SSU2Addr) String() string

String returns a string representation of the SSU2 address. Format: "ssu2://[router_hash]:[conn_id]/[role]/[udp_address][?dest=dest_hash][&introducer=introducer_addr]" Router hash is base64 encoded for readability.

func (*SSU2Addr) UnderlyingAddr

func (sa *SSU2Addr) UnderlyingAddr() net.Addr

UnderlyingAddr returns the underlying UDP network address.

func (*SSU2Addr) UpdateRouterHash

func (sa *SSU2Addr) UpdateRouterHash(hash data.Hash)

UpdateRouterHash replaces the router hash with the given value. This is used after the handshake completes to replace the placeholder hash with one derived from the peer's authenticated static key.

func (*SSU2Addr) WithDestinationHash

func (sa *SSU2Addr) WithDestinationHash(destHash data.Hash) *SSU2Addr

WithDestinationHash sets the destination hash for tunnel connections. Returns a new SSU2Addr instance (immutable pattern).

func (*SSU2Addr) WithIntroducer

func (sa *SSU2Addr) WithIntroducer(introducerAddr net.Addr) (*SSU2Addr, error)

WithIntroducer sets the introducer address for NAT traversal. introducerAddr is the UDP address of the introducer service. Returns a new SSU2Addr instance (immutable pattern).

type SSU2Config

type SSU2Config struct {
	// Pattern is the Noise protocol pattern for SSU2
	// Default: "XK" (standard SSU2 pattern)
	Pattern string

	// Initiator indicates if this connection is the handshake initiator
	// For listeners, this is always false
	Initiator bool

	// RouterHash is the local router identity hash
	// Required for SSU2 addressing and session establishment
	RouterHash data.Hash

	// StaticKey is the long-term static key for this peer (32 bytes for Curve25519)
	StaticKey []byte

	// LocalRouterInfo is the local router's RouterInfo to transmit during the SSU2
	// handshake (SessionConfirmed message for initiators). This RouterInfo MUST contain
	// an SSU2 RouterAddress with the "s" parameter set to the static public key derived
	// from StaticKey, otherwise the peer will reject the handshake.
	// Required for initiator connections (Initiator=true); optional for responders.
	// If nil or empty, the connection will transmit RouterHash instead (legacy behavior,
	// incompatible with strict static key verification).
	LocalRouterInfo []byte

	// RemoteRouterHash is the remote peer's router identity hash
	// Used for identity verification, optional for listeners
	RemoteRouterHash *data.Hash

	// RemoteStaticKey is the remote peer's X25519 static public key (32 bytes).
	// Required for initiator connections (XK pattern requires pre-knowledge of
	// the responder's static key). This is NOT the router hash — it is the "s"
	// parameter from the peer's RouterAddress options.
	RemoteStaticKey []byte

	// HandshakeTimeout is the maximum time to wait for handshake completion
	// Default: 15 seconds (per SSU2 specification)
	HandshakeTimeout time.Duration

	// ReadTimeout is the timeout for read operations after handshake
	// Default: no timeout (0)
	ReadTimeout time.Duration

	// WriteTimeout is the timeout for write operations after handshake
	// Default: no timeout (0)
	WriteTimeout time.Duration

	// HandshakeRetries is the number of handshake retry attempts
	// Default: 3 attempts (0 = no retries, -1 = infinite retries)
	HandshakeRetries int

	// RetryBackoff is the base delay between retry attempts
	// Actual delay uses exponential backoff: delay = RetryBackoff * (2^attempt)
	// Default: 1 second
	RetryBackoff time.Duration

	// EnableChaChaObfuscation enables ChaCha20-based ephemeral key obfuscation
	// Default: true (recommended for production)
	EnableChaChaObfuscation bool

	// ObfuscationIV is the 8-byte IV for ChaCha20 obfuscation
	// If nil, will be derived from router hash (recommended)
	ObfuscationIV []byte

	// MTU is the Maximum Transmission Unit for UDP packets
	// Default: 1280 bytes (IPv6 minimum MTU)
	// Range: 1280-1500 bytes
	MTU int

	// MaxPacketSize is the maximum UDP packet size to send/receive
	// Default: 1500 bytes (typical Ethernet MTU)
	MaxPacketSize int

	// EnableFragmentation allows splitting large messages across multiple packets
	// Default: false (handle at SSU2 layer)
	EnableFragmentation bool

	// PaddingEnabled enables random padding in SSU2 frames
	// Default: true (recommended for traffic analysis resistance)
	PaddingEnabled bool

	// MinPaddingSize is the minimum padding size for frames
	// Default: 0 bytes
	MinPaddingSize int

	// MaxPaddingSize is the maximum padding size for frames
	// Default: 64 bytes
	MaxPaddingSize int

	// PaddingRatio is the padding amount as ratio of data size
	// Valid range: 0.0 to 15.9375 (I2P specification)
	// Default: 1.0 (100% of data size)
	PaddingRatio float64

	// ConnectionID is the 8-byte SSU2 connection identifier
	// If 0, will be generated randomly
	ConnectionID uint64

	// KeepaliveInterval is the time between keepalive packets
	// UDP requires active keepalive to maintain connection state
	// Default: 15 seconds
	KeepaliveInterval time.Duration

	// Modifiers is a list of additional handshake modifiers for custom obfuscation
	// These are applied in addition to SSU2's standard modifiers
	// Default: empty (no additional modifiers)
	Modifiers []handshake.HandshakeModifier

	// IntroKey is the local router's intro key for header protection (32 bytes).
	// If nil, header protection is disabled (headers sent in plaintext).
	IntroKey []byte

	// RemoteIntroKey is the remote peer's intro key for header protection (32 bytes).
	// Required for initiator when IntroKey is set; optional for responder.
	RemoteIntroKey []byte

	// InitiatorConnectionID is the initiator's source connection ID, used by
	// the responder to construct the Noise prologue for handshake binding.
	// Set by the listener when creating a responder connection.
	InitiatorConnectionID uint64

	// RequireRetry, when true, causes the listener to send a Retry message
	// in response to SessionRequest packets that do not carry a valid token.
	// This implements SSU2 source-address validation: the responder sends
	// Retry with a token, and the initiator must resend SessionRequest
	// including that token before the handshake proceeds.
	// Default: false (accept SessionRequest without token)
	RequireRetry bool

	// IdleTimeout is the maximum duration without activity before the
	// connection is closed. The spec does not mandate a specific value.
	// Default: 5 minutes.
	IdleTimeout time.Duration

	// FragmentTimeout is the duration after which incomplete fragment sets
	// are discarded by the DataHandler. The SSU2 spec does not prescribe
	// a specific value; 10 seconds matches the Java I2P default (M-4).
	// Default: 10 seconds.
	FragmentTimeout time.Duration

	// TokenCacheMaxSize is the maximum number of retry tokens the listener
	// will cache. Under high connection rates, a small cache can evict
	// legitimate tokens before use.
	// Default: 10000.
	TokenCacheMaxSize int

	// GlobalTokenIssuanceRate caps the total number of retry tokens the
	// listener will issue per second across ALL source addresses. This
	// backstops the per-IP rate limiter so that a UDP-spoofing attacker
	// who fans out across many source addresses still cannot amplify
	// issuance beyond the configured rate.
	// Default: 40 tokens/sec.
	// Set to 0 to disable token issuance entirely (listener will refuse
	// all Retry/TokenRequest flows). Set to a very large value to
	// effectively disable the cap.
	GlobalTokenIssuanceRate float64

	// GlobalTokenIssuanceBurst is the burst capacity of the global token
	// issuance bucket. Short spikes up to this many tokens can be issued
	// instantaneously before rate limiting applies.
	// Default: max(GlobalTokenIssuanceRate, 80). Ignored when
	// GlobalTokenIssuanceRate == 0.
	GlobalTokenIssuanceBurst float64

	// FirstSightRequired, when true, causes the listener to decline the
	// first TokenRequest from a previously-unseen source address and
	// record the sighting in a cheap, bounded tracker. A token is only
	// issued on the second (or subsequent) TokenRequest from the same
	// address within FirstSightWindow. SSU2 clients already retry
	// TokenRequests with backoff per spec, so legitimate peers recover
	// transparently on the next retry.
	// This defends against off-path spoofed-source token-cache
	// exhaustion: an attacker pays two packets per spoofed address
	// instead of one, and the first-sight tracker entries are smaller
	// than full Token cache entries and live in a separate bounded map.
	// Default: true.
	FirstSightRequired bool

	// FirstSightWindow is the time a first-sight record stays fresh. A
	// peer that re-contacts within this window will be granted a token
	// (subject to other limits). Older entries are treated as first evicted.
	// Default: 30 seconds.
	FirstSightWindow time.Duration

	// FirstSightMaxEntries bounds the memory held by the first-sight
	// tracker. When full, the oldest sighting is evicted.
	// Default: 50000.
	FirstSightMaxEntries int

	// DestroyTimeout is the time to wait after sending a Termination block
	// before releasing session resources. Per spec §Termination, this gives
	// the remote peer time to receive and acknowledge the close.
	// Default: 11 seconds (max RTO per spec). Set to 0 to skip the wait (e.g. in tests).
	DestroyTimeout time.Duration

	// EnableNextNonce enables the NextNonce rekey mechanism (block type 11).
	// WARNING: The SSU2 spec has NOT finalized this block's format or
	// semantics (marked "TODO" with size "TBD"). Enabling this risks
	// breaking interoperability with peers that implement a different
	// (or no) rekey protocol.
	//
	// SECURITY TRADE-OFF: When disabled (default), long-lived sessions hold
	// the same send/receive cipher keys for their entire lifetime. Without
	// mid-session key rotation, forward secrecy is not refreshed — an attacker
	// who later compromises the static key can decrypt the entire session
	// retroactively. For a router holding sessions for weeks, this is a real
	// forward-secrecy gap. Nonce exhaustion guards (elsewhere) mitigate the
	// risk of nonce reuse, but forward secrecy is not recovered until the
	// session closes and a new one is established.
	//
	// Default: false (disabled until spec is finalized) (M-2).
	EnableNextNonce bool

	// ReplayCacheTTL is the time-to-live for entries in the handshake replay
	// cache. The spec does not mandate a specific value; 4 minutes is a
	// reasonable default for the handshake window.
	// Default: 4 minutes (M-2).
	ReplayCacheTTL time.Duration

	// MaxClockSkew is the maximum allowed difference between local and
	// remote clocks for handshake timestamp validation (G-1). Per the SSU2
	// spec, the receiver should verify that the DateTime block timestamp is
	// within a certain window of local time.
	// Default: 120 seconds. Set to 0 to disable skew validation.
	MaxClockSkew time.Duration

	// ReceiveWindowSize is the maximum number of out-of-order packets
	// buffered by the receive window. Larger values improve throughput
	// on lossy links at the cost of memory (M-3).
	// Default: 256. Use 0 for DefaultMaxWindowSize (512).
	ReceiveWindowSize int

	// RouterInfoValidator is a callback invoked after the handshake
	// completes on the responder side. It receives the raw RouterInfo block
	// from SessionConfirmed and the Noise-authenticated static public key.
	// The validator MUST verify that the RouterInfo's identity key corresponds
	// to the static key authenticated by the Noise handshake (C-2).
	// Required for responder configs (Initiator=false); use
	// DefaultRouterInfoValidator or provide a custom implementation.
	RouterInfoValidator func(routerInfo, authenticatedStaticKey []byte) error
}

SSU2Config contains configuration for creating SSU2 connections and listeners. SSU2 (Secure Semi-reliable UDP version 2) is I2P's UDP-based transport protocol. It follows the builder pattern for optional configuration and validation.

func NewSSU2Config

func NewSSU2Config(routerHash data.Hash, initiator bool) (*SSU2Config, error)

NewSSU2Config creates a new SSU2Config with sensible defaults. routerHash is the local router identity hash. initiator indicates whether this connection will initiate the handshake.

func (*SSU2Config) ToConnConfig

func (sc *SSU2Config) ToConnConfig() (*noise.ConnConfig, error)

ToConnConfig converts SSU2Config to a standard ConnConfig for use with NoiseConn. This includes setting up SSU2-specific modifiers based on the configuration.

func (*SSU2Config) Validate

func (sc *SSU2Config) Validate() error

Validate checks if the configuration is valid for SSU2.

func (*SSU2Config) WithChaChaObfuscation

func (sc *SSU2Config) WithChaChaObfuscation(enabled bool, customIV []byte) *SSU2Config

WithChaChaObfuscation enables or disables ChaCha20-based ephemeral key obfuscation. When enabled with a custom IV, the IV must be exactly 8 bytes.

func (*SSU2Config) WithConnectionID

func (sc *SSU2Config) WithConnectionID(connID uint64) *SSU2Config

WithConnectionID sets the SSU2 connection identifier. If connID is 0, a random ID will be generated during connection creation.

func (*SSU2Config) WithDestroyTimeout

func (sc *SSU2Config) WithDestroyTimeout(timeout time.Duration) *SSU2Config

WithDestroyTimeout sets the time to wait after sending a Termination block before releasing session resources. Set to 0 to skip the wait (e.g. in tests).

func (*SSU2Config) WithFirstSightMaxEntries

func (sc *SSU2Config) WithFirstSightMaxEntries(maxEntries int) *SSU2Config

WithFirstSightMaxEntries bounds the memory held by the first-sight tracker. Values <= 0 are ignored.

func (*SSU2Config) WithFirstSightRequired

func (sc *SSU2Config) WithFirstSightRequired(required bool) *SSU2Config

WithFirstSightRequired controls whether the listener requires a previously observed sighting before issuing a token. When true (the default), a brand-new source address must re-request to receive a token. Setting this to false disables the gate entirely.

func (*SSU2Config) WithFirstSightWindow

func (sc *SSU2Config) WithFirstSightWindow(window time.Duration) *SSU2Config

WithFirstSightWindow sets how long a first-sight record stays fresh. Values <= 0 are ignored.

func (*SSU2Config) WithFragmentTimeout

func (sc *SSU2Config) WithFragmentTimeout(timeout time.Duration) *SSU2Config

WithFragmentTimeout sets the duration after which incomplete fragment sets are discarded.

func (*SSU2Config) WithGlobalTokenIssuanceBurst

func (sc *SSU2Config) WithGlobalTokenIssuanceBurst(burst float64) *SSU2Config

WithGlobalTokenIssuanceBurst sets the burst capacity of the global token-issuance bucket. Values <= 0 are ignored (the default is preserved).

func (*SSU2Config) WithGlobalTokenIssuanceRate

func (sc *SSU2Config) WithGlobalTokenIssuanceRate(rate float64) *SSU2Config

WithGlobalTokenIssuanceRate sets the global cap on retry-token issuance across all source addresses (tokens/sec). Pass 0 to disable issuance entirely. Negative values are clamped to 0.

func (*SSU2Config) WithHandshakeRetries

func (sc *SSU2Config) WithHandshakeRetries(retries int) *SSU2Config

WithHandshakeRetries sets the number of handshake retry attempts. Use 0 for no retries, -1 for infinite retries.

func (*SSU2Config) WithHandshakeTimeout

func (sc *SSU2Config) WithHandshakeTimeout(timeout time.Duration) *SSU2Config

WithHandshakeTimeout sets the handshake timeout.

func (*SSU2Config) WithIdleTimeout

func (sc *SSU2Config) WithIdleTimeout(timeout time.Duration) *SSU2Config

WithIdleTimeout sets the idle timeout after which the connection is closed.

func (*SSU2Config) WithKeepalive

func (sc *SSU2Config) WithKeepalive(interval time.Duration) *SSU2Config

WithKeepalive sets the interval between keepalive packets. UDP connections require active keepalive to maintain state.

func (*SSU2Config) WithLocalRouterInfo

func (sc *SSU2Config) WithLocalRouterInfo(routerInfo []byte) *SSU2Config

WithLocalRouterInfo sets the local RouterInfo to transmit during handshake. The RouterInfo MUST contain an SSU2 RouterAddress with the "s" parameter matching the static public key derived from StaticKey, otherwise peers with strict static key verification will reject the handshake. Required for initiator connections; optional for responders.

func (*SSU2Config) WithMTU

func (sc *SSU2Config) WithMTU(mtu int) *SSU2Config

WithMTU sets the Maximum Transmission Unit for UDP packets. Valid range: 1280-1500 bytes. Default is 1280 (IPv6 minimum).

func (*SSU2Config) WithMaxClockSkew

func (sc *SSU2Config) WithMaxClockSkew(skew time.Duration) *SSU2Config

WithMaxClockSkew sets the maximum allowed clock skew for handshake timestamp validation. Set to 0 to disable skew checking.

func (*SSU2Config) WithModifiers

func (sc *SSU2Config) WithModifiers(modifiers ...handshake.HandshakeModifier) *SSU2Config

WithModifiers sets additional handshake modifiers for custom obfuscation. These are applied in addition to SSU2's standard modifiers.

func (*SSU2Config) WithPacketSettings

func (sc *SSU2Config) WithPacketSettings(maxSize int, fragmentation bool) *SSU2Config

WithPacketSettings configures UDP packet handling parameters. maxSize sets the maximum packet size (default: 1500 bytes). fragmentation enables splitting large messages (default: false).

func (*SSU2Config) WithPaddingSettings

func (sc *SSU2Config) WithPaddingSettings(enabled bool, minPad, maxPad int, ratio float64) *SSU2Config

WithPaddingSettings configures SSU2 frame padding parameters. enabled enables random padding (default: true). minPad and maxPad set the padding size range (default: 0-64 bytes). ratio sets the padding amount as ratio of data size (0.0-15.9375).

func (*SSU2Config) WithPattern

func (sc *SSU2Config) WithPattern(pattern string) *SSU2Config

WithPattern sets the Noise protocol pattern. For SSU2, this should typically remain "XK".

func (*SSU2Config) WithReadTimeout

func (sc *SSU2Config) WithReadTimeout(timeout time.Duration) *SSU2Config

WithReadTimeout sets the read timeout for post-handshake operations.

func (*SSU2Config) WithReceiveWindowSize

func (sc *SSU2Config) WithReceiveWindowSize(size int) *SSU2Config

WithReceiveWindowSize sets the maximum number of out-of-order packets the receive window will buffer. Use 0 for DefaultMaxWindowSize.

func (*SSU2Config) WithRemoteRouterHash

func (sc *SSU2Config) WithRemoteRouterHash(hash data.Hash) *SSU2Config

WithRemoteRouterHash sets the remote peer's router identity hash. Used for identity verification.

func (*SSU2Config) WithRemoteStaticKey

func (sc *SSU2Config) WithRemoteStaticKey(key []byte) *SSU2Config

WithRemoteStaticKey sets the remote peer's X25519 static public key. Required for initiator connections. The key must be 32 bytes (Curve25519). This is the "s" parameter from the peer's RouterAddress options, NOT the router hash.

func (*SSU2Config) WithRetryBackoff

func (sc *SSU2Config) WithRetryBackoff(backoff time.Duration) *SSU2Config

WithRetryBackoff sets the base delay between retry attempts.

func (*SSU2Config) WithRouterInfoValidator

func (sc *SSU2Config) WithRouterInfoValidator(validator func(routerInfo, authenticatedStaticKey []byte) error) *SSU2Config

WithRouterInfoValidator sets the RouterInfo validation callback. The validator is invoked on the responder after handshake completion to verify that the peer's RouterInfo contains the Noise-authenticated static key.

func (*SSU2Config) WithStaticKey

func (sc *SSU2Config) WithStaticKey(key []byte) *SSU2Config

WithStaticKey sets the static key for this connection. key must be 32 bytes for Curve25519.

func (*SSU2Config) WithTokenCacheMaxSize

func (sc *SSU2Config) WithTokenCacheMaxSize(maxSize int) *SSU2Config

WithTokenCacheMaxSize sets the maximum number of retry tokens cached by the listener.

func (*SSU2Config) WithWriteTimeout

func (sc *SSU2Config) WithWriteTimeout(timeout time.Duration) *SSU2Config

WithWriteTimeout sets the write timeout for post-handshake operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL