p2p

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Apr 9, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package p2p provides peer-to-peer direct connection capabilities.

The p2p package implements NAT traversal techniques to establish direct connections between clients when possible, falling back to server relay when P2P fails.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConnectionMode

type ConnectionMode int

ConnectionMode represents how the connection is established.

const (
	// ModeRelay means traffic goes through the server (default).
	ModeRelay ConnectionMode = iota
	// ModeP2P means a direct UDP connection was established.
	ModeP2P
)

func (ConnectionMode) String

func (m ConnectionMode) String() string

String returns the connection mode name.

type Endpoint

type Endpoint struct {
	IP   string `json:"ip"`
	Port int    `json:"port"`
}

Endpoint represents a network endpoint with IP and port.

func (Endpoint) String

func (e Endpoint) String() string

String returns the endpoint as host:port.

type HolePunchConfig

type HolePunchConfig struct {
	// MaxAttempts is the maximum number of punch attempts.
	MaxAttempts int
	// Interval is the delay between punch attempts.
	Interval time.Duration
	// Timeout is the overall timeout for the hole punch operation.
	Timeout time.Duration
}

HolePunchConfig holds configuration for UDP hole punching.

func DefaultHolePunchConfig

func DefaultHolePunchConfig() HolePunchConfig

DefaultHolePunchConfig returns sensible defaults.

type HolePuncher

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

HolePuncher performs UDP hole punching between two peers.

func NewHolePuncher

func NewHolePuncher(config HolePunchConfig) *HolePuncher

NewHolePuncher creates a new hole puncher.

func (*HolePuncher) Punch

func (h *HolePuncher) Punch(ctx context.Context, localConn net.PacketConn, peerEndpoint Endpoint) (*net.UDPAddr, error)

Punch attempts to establish a UDP connection to the peer via hole punching. It sends probe packets to the peer's public endpoint while simultaneously listening for incoming probes. Returns the established connection if successful.

func (*HolePuncher) SetCipher

func (h *HolePuncher) SetCipher(c *SessionCipher)

SetCipher sets the session cipher for authenticated hole punching.

type KeyPair

type KeyPair struct {
	// Private is the ECDH private key.
	Private *ecdh.PrivateKey
	// Public is the ECDH public key (raw 32-byte X25519 representation).
	Public []byte
}

KeyPair holds an ECDH X25519 key pair for key exchange.

func GenerateKeyPair

func GenerateKeyPair() (*KeyPair, error)

GenerateKeyPair generates a new X25519 ECDH key pair.

type Manager

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

Manager coordinates P2P connection establishment and fallback.

func NewManager

func NewManager(config ManagerConfig) *Manager

NewManager creates a new P2P manager.

func (*Manager) AttemptP2P

func (m *Manager) AttemptP2P(ctx context.Context, peerEndpoint Endpoint, cipher *SessionCipher) (net.PacketConn, *net.UDPAddr, error)

AttemptP2P tries to establish a P2P connection with a peer. It returns the established UDP connection or an error (caller should fallback to relay). If a SessionCipher is provided, hole-punch probes will be HMAC-authenticated.

func (*Manager) FallbackToRelay

func (m *Manager) FallbackToRelay(reason string)

FallbackToRelay switches back to relay mode.

func (*Manager) Init

func (m *Manager) Init(ctx context.Context) error

Init performs initial NAT discovery. Should be called once at startup.

func (*Manager) IsEnabled

func (m *Manager) IsEnabled() bool

IsEnabled returns whether P2P is enabled and NAT is traversable.

func (*Manager) Mode

func (m *Manager) Mode() ConnectionMode

Mode returns the current connection mode.

func (*Manager) NATInfo

func (m *Manager) NATInfo() *NATInfo

NATInfo returns the discovered NAT info, or nil if not yet discovered.

type ManagerConfig

type ManagerConfig struct {
	// Enabled controls whether P2P is attempted.
	Enabled bool
	// STUNConfig is the STUN client configuration.
	STUNConfig STUNConfig
	// HolePunchConfig is the hole punch configuration.
	HolePunchConfig HolePunchConfig
	// FallbackTimeout is how long to wait before falling back to relay.
	FallbackTimeout time.Duration
}

ManagerConfig holds configuration for the P2P manager.

func DefaultManagerConfig

func DefaultManagerConfig() ManagerConfig

DefaultManagerConfig returns sensible defaults.

type NATInfo

type NATInfo struct {
	// Type is the detected NAT type.
	Type NATType `json:"type"`
	// PublicAddr is the public-facing endpoint as seen by the STUN server.
	PublicAddr Endpoint `json:"public_addr"`
	// LocalAddr is the local endpoint used for the STUN request.
	LocalAddr Endpoint `json:"local_addr"`
}

NATInfo contains the results of NAT discovery.

type NATType

type NATType int

NATType represents the type of NAT detected.

const (
	// NATUnknown indicates the NAT type could not be determined.
	NATUnknown NATType = iota
	// NATNone indicates no NAT — the host has a public IP.
	NATNone
	// NATFullCone indicates a full cone (one-to-one) NAT.
	NATFullCone
	// NATRestrictedCone indicates a restricted cone NAT.
	NATRestrictedCone
	// NATPortRestricted indicates a port-restricted cone NAT.
	NATPortRestricted
	// NATSymmetric indicates a symmetric NAT (hardest to traverse).
	NATSymmetric
)

func (NATType) IsTraversable

func (n NATType) IsTraversable() bool

IsTraversable returns whether P2P hole punching is likely to succeed.

func (NATType) String

func (n NATType) String() string

String returns a human-readable NAT type name.

type Predictor

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

Predictor predicts the next external port for symmetric NAT traversal.

Symmetric NATs assign a new external port for each unique (dest IP, dest port) tuple. Some implementations increment ports sequentially, making prediction possible. This is a heuristic and may not work for all NAT implementations.

func NewPredictor

func NewPredictor() *Predictor

NewPredictor creates a new port predictor.

func (*Predictor) AddSample

func (p *Predictor) AddSample(port int)

AddSample adds an observed external port to the predictor.

func (*Predictor) Predict

func (p *Predictor) Predict(count int) []int

Predict returns a list of candidate ports that the peer's NAT might use. It uses delta-based prediction and adds randomized candidates around the predicted range for better coverage.

type STUNClient

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

STUNClient performs STUN binding requests to discover the public endpoint.

func NewSTUNClient

func NewSTUNClient(config STUNConfig) *STUNClient

NewSTUNClient creates a new STUN client.

func (*STUNClient) Discover

func (s *STUNClient) Discover(ctx context.Context) (*NATInfo, error)

Discover performs NAT discovery by querying STUN servers. It returns the detected NAT type and public endpoint.

func (*STUNClient) DiscoverEndpoint

func (s *STUNClient) DiscoverEndpoint(ctx context.Context) (*Endpoint, error)

DiscoverEndpoint performs a simple STUN binding request to get the public endpoint. This is faster than full Discover() and sufficient when NAT type is not needed.

type STUNConfig

type STUNConfig struct {
	// Servers is a list of STUN server addresses.
	Servers []string
	// Timeout is the deadline for each STUN request.
	Timeout time.Duration
	// Retries is the number of retry attempts per server.
	Retries int
}

STUNConfig holds STUN client configuration.

func DefaultSTUNConfig

func DefaultSTUNConfig() STUNConfig

DefaultSTUNConfig returns sensible defaults for STUN discovery.

type SessionCipher

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

SessionCipher provides authenticated encryption for a P2P session. It uses AES-256-GCM with a monotonic nonce derived from a sequence counter.

func DeriveSession

func DeriveSession(localPriv *ecdh.PrivateKey, remotePubBytes []byte) (*SessionCipher, error)

DeriveSession performs ECDH key agreement and derives session keys. It takes the local private key and the remote peer's public key bytes, and returns a SessionCipher ready for encrypting/decrypting data.

func (*SessionCipher) Decrypt

func (sc *SessionCipher) Decrypt(data []byte) ([]byte, error)

Decrypt decrypts data produced by Encrypt. Input format: [8-byte nonce counter][GCM ciphertext+tag].

func (*SessionCipher) Encrypt

func (sc *SessionCipher) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext using AES-256-GCM with a unique nonce. The output format is: [8-byte nonce counter][GCM ciphertext+tag].

func (*SessionCipher) Overhead

func (sc *SessionCipher) Overhead() int

Overhead returns the total byte overhead added by encryption. This is 8 (nonce counter) + GCM tag size (16) = 24 bytes.

func (*SessionCipher) SignProbe

func (sc *SessionCipher) SignProbe(payload []byte) []byte

SignProbe creates an HMAC-SHA256 signature for a hole-punch probe payload. The caller should append this tag to the probe packet.

func (*SessionCipher) VerifyProbe

func (sc *SessionCipher) VerifyProbe(payload, tag []byte) bool

VerifyProbe verifies the HMAC-SHA256 signature on a hole-punch probe.

type Transport

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

Transport provides a reliable stream-like interface over UDP. It implements a simple ARQ (Automatic Repeat reQuest) protocol for data reliability over the unreliable UDP connection. When a SessionCipher is set, all data packets are encrypted with AES-256-GCM, providing confidentiality and integrity.

func NewTransport

func NewTransport(conn net.PacketConn, peerAddr *net.UDPAddr, config TransportConfig, cipher *SessionCipher) *Transport

NewTransport creates a new UDP transport. An optional SessionCipher enables end-to-end encryption for all data packets.

func (*Transport) Close

func (t *Transport) Close() error

Close closes the transport.

func (*Transport) IsEncrypted

func (t *Transport) IsEncrypted() bool

IsEncrypted returns whether this transport is using end-to-end encryption.

func (*Transport) LocalAddr

func (t *Transport) LocalAddr() net.Addr

LocalAddr returns the local address.

func (*Transport) Read

func (t *Transport) Read(buf []byte) (int, error)

Read receives data from the peer.

func (*Transport) RemoteAddr

func (t *Transport) RemoteAddr() net.Addr

RemoteAddr returns the peer address.

func (*Transport) Stats

func (t *Transport) Stats() TransportStats

Stats returns transport statistics.

func (*Transport) Write

func (t *Transport) Write(data []byte) (int, error)

Write sends data to the peer with reliability.

type TransportConfig

type TransportConfig struct {
	// MaxPacketSize is the maximum UDP packet size.
	MaxPacketSize int
	// RetransmitTimeout is the timeout before retransmitting a packet.
	RetransmitTimeout time.Duration
	// MaxRetransmits is the maximum number of retransmissions before giving up.
	MaxRetransmits int
	// AckTimeout is the timeout for waiting for an ACK.
	AckTimeout time.Duration
	// RecvBufferSize is the size of the receive channel buffer.
	RecvBufferSize int
}

TransportConfig holds configuration for the UDP transport.

func DefaultTransportConfig

func DefaultTransportConfig() TransportConfig

DefaultTransportConfig returns sensible defaults.

type TransportStats

type TransportStats struct {
	SendSeq     uint32
	RecvSeq     uint32
	PendingAcks int
	OutOfOrder  int
}

TransportStats contains transport statistics.

Jump to

Keyboard shortcuts

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