proxyudp

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package proxyudp implements VORTEX's UDP tunnel (build plan M2.5): a session-tracking forwarder for connectionless UDP traffic with a per-source-IP token-bucket rate limiter. UDP has no connection concept, so client→backend "sessions" are tracked manually by client address and reaped after an idle TTL. Standard library only (Non-Negotiable Rule #10).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type RateLimiter

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

RateLimiter applies a per-source-IP token bucket: each IP may send `rate` packets per second sustained, bursting up to `burst` packets. Packets over the limit are dropped (Allow returns false).

func NewRateLimiter

func NewRateLimiter(rate, burst int) (*RateLimiter, error)

NewRateLimiter builds a limiter allowing `rate` packets/sec per IP with a burst capacity of `burst`. Both must be positive.

func (*RateLimiter) Allow

func (r *RateLimiter) Allow(ip string) bool

Allow reports whether a packet from ip may be forwarded, consuming a token if so. It refills the bucket based on elapsed time, caps it at burst, and returns false (drop) when fewer than one token is available.

func (*RateLimiter) StartCleanup

func (r *RateLimiter) StartCleanup(ctx context.Context)

StartCleanup runs a goroutine that removes buckets unused for 10 minutes, sweeping every 5 minutes, until ctx is cancelled. This bounds memory under traffic from many distinct source IPs.

type Session

type Session struct {
	ClientAddr  *net.UDPAddr
	BackendConn *net.UDPConn

	BytesIn  atomic.Int64 // client → backend
	BytesOut atomic.Int64 // backend → client
	// contains filtered or unexported fields
}

Session is one client's UDP flow: a backend connection plus liveness and byte counters. LastSeen is stored as a Unix-nano atomic so concurrent reader (sweeper) and writers (read loop, reply pump) need no lock.

func (*Session) LastSeen

func (s *Session) LastSeen() time.Time

LastSeen returns the time of the most recent activity on the session.

type SessionStats

type SessionStats struct {
	Active  int
	Total   int64
	Cleaned int64
}

SessionStats is a snapshot of session-table counters.

type SessionTable

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

SessionTable tracks active UDP sessions keyed by client address string.

func NewSessionTable

func NewSessionTable(ttl time.Duration) *SessionTable

NewSessionTable returns a table with the given idle TTL (default 30s).

func (*SessionTable) ActiveCount

func (t *SessionTable) ActiveCount() int

ActiveCount returns the number of live sessions.

func (*SessionTable) CloseAll

func (t *SessionTable) CloseAll()

CloseAll deletes and closes every session. It is used on listener shutdown to unblock reply pumps (which are reading on the per-session backend conns).

func (*SessionTable) Delete

func (t *SessionTable) Delete(clientAddr string)

Delete removes and closes the session for the given client-address key.

func (*SessionTable) GetOrCreate

func (t *SessionTable) GetOrCreate(clientAddr *net.UDPAddr, backendAddr string) (*Session, bool, error)

GetOrCreate returns the session for clientAddr, creating one (dialing backendAddr) if none exists. The bool is true when a new session was created.

func (*SessionTable) StartCleanup

func (t *SessionTable) StartCleanup(ctx context.Context)

StartCleanup runs a goroutine that reaps idle sessions every ttl/2 until ctx is cancelled.

func (*SessionTable) Stats

func (t *SessionTable) Stats() SessionStats

Stats returns a snapshot of table counters.

func (*SessionTable) Touch

func (t *SessionTable) Touch(clientAddr string)

Touch updates LastSeen for the session with the given client-address key.

type UDPListener

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

UDPListener forwards UDP datagrams to a backend, tracking per-client sessions and rate-limiting by source IP.

func NewListener

func NewListener(cfg UDPListenerConfig) (*UDPListener, error)

NewListener validates cfg and constructs a UDPListener.

func (*UDPListener) Listen

func (l *UDPListener) Listen(ctx context.Context) error

Listen binds the UDP socket and forwards datagrams until ctx is cancelled. It starts the session and rate-limiter cleanup goroutines, runs the read loop, and on cancellation closes the socket and all sessions. It returns nil on clean shutdown.

func (*UDPListener) LocalAddr

func (l *UDPListener) LocalAddr() string

LocalAddr returns the bound UDP address once Listen has bound the socket, or "" before then. Safe for concurrent use.

func (*UDPListener) Stats

func (l *UDPListener) Stats() UDPStats

Stats returns a snapshot of the listener's counters.

type UDPListenerConfig

type UDPListenerConfig struct {
	// ListenAddr is the local UDP bind address, e.g. ":53".
	ListenAddr string
	// BackendAddr is the upstream UDP target, "host:port".
	BackendAddr string
	// MaxSessions caps concurrent client sessions. Default 10000.
	MaxSessions int
	// RateLimit is sustained packets/sec per source IP; 0 disables limiting.
	RateLimit int
	// RateBurst is the burst size; defaults to RateLimit*2 when unset.
	RateBurst int
	// SessionTTL is the idle timeout before a session is reaped. Default 30s.
	SessionTTL time.Duration
	// BufferSize is the per-read datagram buffer. Default 64KiB.
	BufferSize int
	// Logger receives diagnostics; defaults to slog.Default.
	Logger *slog.Logger
}

UDPListenerConfig configures a UDPListener.

type UDPStats

type UDPStats struct {
	Sessions SessionStats
	Dropped  int64 // rate-limited + max-sessions drops
}

UDPStats is a snapshot of UDP listener counters.

Jump to

Keyboard shortcuts

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