Documentation
¶
Overview ¶
Package server implements a production-grade SOCKS5 server (RFC 1928) with CONNECT, BIND and UDP ASSOCIATE, pluggable authentication, rules, resolvers, middleware, metrics, admission control and graceful shutdown. On Linux the TCP relay uses splice(2) via io.Copy fast paths and the UDP relay moves batches of datagrams per syscall (recvmmsg/sendmmsg).
Index ¶
- Variables
- func SendReply(w io.Writer, rep uint8, bindAddr net.Addr) error
- type ConnState
- type CounterMetrics
- func (m *CounterMetrics) ConnAccepted()
- func (m *CounterMetrics) ConnClosed()
- func (m *CounterMetrics) ConnRejected(RejectReason)
- func (m *CounterMetrics) RelayBytes(n int64)
- func (m *CounterMetrics) Request(byte)
- func (m *CounterMetrics) RequestDone(_ byte, err error)
- func (m *CounterMetrics) Snapshot() MetricsSnapshot
- type GPool
- type Logger
- type Metrics
- type MetricsSnapshot
- type Option
- func WithAssociateHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
- func WithAssociateMiddleware(m handler.Middleware) Option
- func WithAuthMethods(authMethods []auth.Authenticator) Option
- func WithBaseContext(fn func(net.Listener) context.Context) Option
- func WithBindAcceptTimeout(d time.Duration) Option
- func WithBindHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
- func WithBindIP(ip net.IP) Option
- func WithBindMiddleware(m handler.Middleware) Option
- func WithBindPeerCheckIPOnly(b bool) Option
- func WithBufferPool(pool buffer.BufPool) Option
- func WithConnContext(fn func(ctx context.Context, conn net.Conn) context.Context) Option
- func WithConnMetadata(fn func(net.Conn) map[string]string) Option
- func WithConnState(fn func(net.Conn, ConnState)) Option
- func WithConnectHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
- func WithConnectMiddleware(m handler.Middleware) Option
- func WithConnectionLogging(enabled bool) Option
- func WithConnectionRateLimit(perSecond float64, burst int) Option
- func WithCredential(cs auth.CredentialStore) Option
- func WithDial(dial func(ctx context.Context, network, addr string) (net.Conn, error)) Option
- func WithDialAndRequest(...) Option
- func WithDialFQDN(enabled bool) Option
- func WithDialer(d net.Dialer) Option
- func WithGPool(pool GPool) Option
- func WithHandshakeTimeout(d time.Duration) Option
- func WithLinkQuality(tr *linkquality.Tracker) Option
- func WithLogger(l Logger) Option
- func WithMaxConnections(n int) Option
- func WithMetrics(m Metrics) Option
- func WithResolver(res resolver.NameResolver) Option
- func WithRewriter(rew handler.AddressRewriter) Option
- func WithRule(rule rules.RuleSet) Option
- func WithTCPKeepAlive(period time.Duration) Option
- func WithUDPAssociateLimits(maxPeers int, idleTimeout time.Duration) Option
- func WithUseBindIpBaseResolveAsUdpAddr(b bool) Option
- type RejectReason
- type Server
- func (sf *Server) Close() error
- func (sf *Server) LinkQualityTracker() *linkquality.Tracker
- func (sf *Server) ListenAndServe(network, addr string) error
- func (sf *Server) ListenAndServeTLS(network, addr string, c *tls.Config) error
- func (sf *Server) Proxy(dst io.Writer, src io.Reader) error
- func (sf *Server) Serve(l net.Listener) error
- func (sf *Server) ServeConn(conn net.Conn) error
- func (sf *Server) ServeConnContext(ctx context.Context, conn net.Conn) error
- func (sf *Server) ServeContext(ctx context.Context, l net.Listener) error
- func (sf *Server) Shutdown(ctx context.Context) error
- type SlogLogger
- type Std
Constants ¶
This section is empty.
Variables ¶
var ErrServerClosed = errors.New("socks5: server closed")
ErrServerClosed is returned by Serve, ServeContext, ListenAndServe and ListenAndServeTLS after a call to Shutdown or Close.
Functions ¶
Types ¶
type ConnState ¶ added in v0.3.2
type ConnState int
ConnState describes a connection lifecycle phase reported to the WithConnState hook.
const ( // StateNew is reported right after the accept loop admits a connection. StateNew ConnState = iota // StateActive is reported when the SOCKS handshake begins. StateActive // StateClosed is reported after the connection finishes. StateClosed )
Connection lifecycle states, in order of occurrence.
type CounterMetrics ¶ added in v1.0.0
type CounterMetrics struct {
// contains filtered or unexported fields
}
CounterMetrics is a ready-to-use Metrics implementation backed by atomic counters. It is suitable for tests, expvar publishing, or as a starting point for custom backends.
func (*CounterMetrics) ConnAccepted ¶ added in v1.0.0
func (m *CounterMetrics) ConnAccepted()
ConnAccepted implements Metrics.
func (*CounterMetrics) ConnClosed ¶ added in v1.0.0
func (m *CounterMetrics) ConnClosed()
ConnClosed implements Metrics.
func (*CounterMetrics) ConnRejected ¶ added in v1.0.0
func (m *CounterMetrics) ConnRejected(RejectReason)
ConnRejected implements Metrics.
func (*CounterMetrics) RelayBytes ¶ added in v1.0.0
func (m *CounterMetrics) RelayBytes(n int64)
RelayBytes implements Metrics.
func (*CounterMetrics) Request ¶ added in v1.0.0
func (m *CounterMetrics) Request(byte)
Request implements Metrics.
func (*CounterMetrics) RequestDone ¶ added in v1.0.0
func (m *CounterMetrics) RequestDone(_ byte, err error)
RequestDone implements Metrics.
func (*CounterMetrics) Snapshot ¶ added in v1.0.0
func (m *CounterMetrics) Snapshot() MetricsSnapshot
Snapshot returns a consistent-enough copy of all counters for reporting.
type GPool ¶
type GPool interface {
Submit(f func()) error
}
GPool is a goroutine pool abstraction (e.g. ants). When installed with WithGPool, request handling is submitted to the pool instead of spawning a goroutine per task; a Submit error falls back to `go`.
type Logger ¶
type Logger interface {
// Infof logs an informational message in fmt.Printf style.
Infof(format string, args ...any)
// Errorf logs an error message in fmt.Printf style.
Errorf(format string, args ...any)
}
Logger is the minimal logging interface consumed by the server. Wrap a standard library *log.Logger with NewLogger or a *slog.Logger with NewSlogLogger, or provide your own implementation via WithLogger.
type Metrics ¶ added in v1.0.0
type Metrics interface {
// ConnAccepted is called when the accept loop admits a connection.
ConnAccepted()
// ConnClosed is called when an admitted connection finishes.
ConnClosed()
// ConnRejected is called when the accept loop refuses a connection
// before the handshake (connection cap or rate limit).
ConnRejected(reason RejectReason)
// Request is called once per parsed SOCKS request with the command byte
// (protocol.CommandConnect, CommandBind or CommandAssociate).
Request(command byte)
// RequestDone is called when the request finishes; err is nil on success.
RequestDone(command byte, err error)
// RelayBytes reports payload bytes moved by the proxy: once per finished
// CONNECT/BIND tunnel (both directions summed) and once per relayed UDP
// batch. The sum over time is total relayed traffic.
RelayBytes(n int64)
}
Metrics receives server lifecycle events for observability backends (Prometheus, OpenTelemetry, expvar, ...). All methods are invoked inline on the serving path, so implementations must be safe for concurrent use and return quickly; anything slow should be offloaded by the implementation.
Install with WithMetrics. When no Metrics is configured the server skips every call site with a single nil check — there is no other overhead.
type MetricsSnapshot ¶ added in v1.0.0
type MetricsSnapshot struct {
Accepted int64 // connections admitted by the accept loop
Closed int64 // admitted connections that have finished
Rejected int64 // connections refused before the handshake
Requests int64 // SOCKS requests started
RequestFails int64 // SOCKS requests that returned an error
RelayedBytes int64 // total payload bytes relayed (TCP tunnels + UDP)
}
MetricsSnapshot is a point-in-time copy of CounterMetrics values.
type Option ¶
type Option func(s *Server)
Option configures a Server at construction time; pass options to New.
func WithAssociateHandle ¶
func WithAssociateHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
WithAssociateHandle replaces the default UDP ASSOCIATE handler.
func WithAssociateMiddleware ¶
func WithAssociateMiddleware(m handler.Middleware) Option
WithAssociateMiddleware appends middleware executed before the UDP ASSOCIATE handler.
func WithAuthMethods ¶
func WithAuthMethods(authMethods []auth.Authenticator) Option
WithAuthMethods appends custom authenticators to the method negotiation list.
func WithBaseContext ¶ added in v0.3.2
WithBaseContext installs a base context factory that is invoked once per listener. ServeContext derives each connection context from the returned value.
func WithBindAcceptTimeout ¶
WithBindAcceptTimeout sets how long the server waits for the peer during BIND.
func WithBindHandle ¶
func WithBindHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
WithBindHandle replaces the default BIND handler.
func WithBindIP ¶
WithBindIP sets the bind address used for BIND/UDP sockets.
func WithBindMiddleware ¶
func WithBindMiddleware(m handler.Middleware) Option
WithBindMiddleware appends middleware executed before the BIND handler.
func WithBindPeerCheckIPOnly ¶
WithBindPeerCheckIPOnly switches peer validation to IP-only (ignoring port).
func WithBufferPool ¶
WithBufferPool sets the buffer pool used by the proxy I/O fast-paths.
func WithConnContext ¶ added in v0.3.2
WithConnContext decorates the per-connection context before handlers and dialers run. The provided ctx is derived from ServeContext; return nil to keep the original value.
func WithConnMetadata ¶ added in v0.3.2
WithConnMetadata installs a callback used to attach static metadata to handler.Request.Metadata. The returned map is shallow-copied per connection.
func WithConnState ¶ added in v0.3.2
WithConnState registers a hook that receives connection lifecycle transitions (StateNew, StateActive, StateClosed).
func WithConnectHandle ¶
func WithConnectHandle(h func(ctx context.Context, writer io.Writer, req *handler.Request) error) Option
WithConnectHandle replaces the default CONNECT handler.
func WithConnectMiddleware ¶
func WithConnectMiddleware(m handler.Middleware) Option
WithConnectMiddleware appends middleware executed before the CONNECT handler.
func WithConnectionLogging ¶ added in v0.4.1
WithConnectionLogging enables or disables per-connection accept/close logs.
func WithConnectionRateLimit ¶ added in v1.0.0
WithConnectionRateLimit limits accepted connections per source IP using a token bucket: each source may open bursts of up to burst connections and sustain perSecond connections per second afterwards. Excess connections are closed before the handshake. perSecond <= 0 disables the limiter; burst < 1 is raised to 1. Memory is bounded under spoofed-source floods: idle buckets are swept once the table grows past an internal threshold.
func WithCredential ¶
func WithCredential(cs auth.CredentialStore) Option
WithCredential provides a credential store used by the default user/pass authenticator.
func WithDialAndRequest ¶
func WithDialAndRequest(dial func(ctx context.Context, network, addr string, req *handler.Request) (net.Conn, error)) Option
WithDialAndRequest is like WithDial but also exposes the parsed request.
func WithDialFQDN ¶ added in v1.0.0
WithDialFQDN controls how CONNECT requests carrying a domain name are dialed. When enabled the server skips its own resolution step and hands the hostname straight to the dialer, restoring the net.Dialer dual-stack "Happy Eyeballs" fallback (RFC 8305) and per-attempt address selection. The configured resolver is then bypassed for CONNECT, and rules, rewriters and middleware observe a request whose DestAddr still carries the FQDN with a nil IP. BIND and UDP ASSOCIATE are unaffected.
func WithDialer ¶
WithDialer sets a custom net.Dialer for outbound connections when a custom dial is not provided.
func WithHandshakeTimeout ¶
WithHandshakeTimeout sets a deadline for initial negotiation and request parsing. Zero disables the handshake deadline.
func WithLinkQuality ¶ added in v0.4.1
func WithLinkQuality(tr *linkquality.Tracker) Option
WithLinkQuality enables link quality tracking for outbound hops.
func WithLogger ¶
WithLogger replaces the server logger implementation.
func WithMaxConnections ¶ added in v1.0.0
WithMaxConnections caps the number of concurrently served connections. When the cap is reached the accept loop closes new connections immediately, before any SOCKS traffic, with an O(1) check. n <= 0 means unlimited.
func WithMetrics ¶ added in v1.0.0
WithMetrics installs a Metrics implementation that receives connection, request and relay events. Pass nil to disable (the default); when disabled the only cost on the serving path is a nil check.
func WithResolver ¶
func WithResolver(res resolver.NameResolver) Option
WithResolver overrides the DNS resolver used for FQDN targets.
func WithRewriter ¶
func WithRewriter(rew handler.AddressRewriter) Option
WithRewriter installs an address rewriter that can mutate the destination before dialing.
func WithTCPKeepAlive ¶
WithTCPKeepAlive enables TCP keepalives on accepted connections with the given period. Zero disables keepalives.
func WithUDPAssociateLimits ¶
WithUDPAssociateLimits configures UDP ASSOCIATE peer limits and idle cleanup. If maxPeers <= 0, unlimited peers are allowed. If idleTimeout <= 0, peers are not GC'd by idle.
func WithUseBindIpBaseResolveAsUdpAddr ¶
WithUseBindIpBaseResolveAsUdpAddr forces UDP ASSOCIATE replies to advertise the bind IP.
type RejectReason ¶ added in v1.0.0
type RejectReason string
RejectReason explains why the accept loop refused a connection before the SOCKS handshake started.
const ( // RejectMaxConnections means the WithMaxConnections cap was reached. RejectMaxConnections RejectReason = "max_connections" // RejectRateLimited means the per-source rate limit configured with // WithConnectionRateLimit was exceeded. RejectRateLimited RejectReason = "rate_limited" )
Rejection reasons reported to Metrics.ConnRejected.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a SOCKS5 server (RFC 1928) supporting CONNECT, BIND and UDP ASSOCIATE. Construct it with New and the With* options; the zero value is not usable. All exported methods are safe for concurrent use.
func New ¶
New builds a Server with the given options. Without WithCredential or WithAuthMethods the server accepts unauthenticated clients (NoAuth).
func (*Server) Close ¶ added in v1.0.0
Close immediately closes all listeners and tears down every active connection. For a graceful stop, use Shutdown.
func (*Server) LinkQualityTracker ¶ added in v0.4.1
func (sf *Server) LinkQualityTracker() *linkquality.Tracker
LinkQualityTracker returns the tracker used for outbound hops, if enabled.
func (*Server) ListenAndServe ¶
ListenAndServe listens on the network address and serves SOCKS5 until the server is shut down. It returns ErrServerClosed after Shutdown or Close.
func (*Server) ListenAndServeTLS ¶
ListenAndServeTLS is ListenAndServe over a TLS listener. With tls.RequireAndVerifyClientCert the client certificate details are exposed to rules and handlers via the auth context (tls.* payload keys).
func (*Server) Proxy ¶
Proxy copies data from src to dst. It prefers optimized io.Copy paths (ReaderFrom/WriterTo) and uses the shared buffer pool for the generic copy case to avoid per-call allocations.
func (*Server) Serve ¶
Serve accepts and serves SOCKS5 connections on l until the server is shut down. It returns ErrServerClosed after Shutdown or Close.
func (*Server) ServeConn ¶
ServeConn serves a single, already-accepted connection. Admission control (WithMaxConnections, WithConnectionRateLimit) is not applied: it belongs to the accept loop, and direct callers manage their own.
func (*Server) ServeConnContext ¶ added in v0.3.2
ServeConnContext is like ServeConn but binds the provided context to the connection lifecycle.
func (*Server) ServeContext ¶ added in v0.3.2
ServeContext serves SOCKS5 on l until ctx is done, Shutdown/Close is called, or an unrecoverable error occurs. Canceling ctx tears down every active connection; Shutdown lets in-flight connections finish.
func (*Server) Shutdown ¶ added in v1.0.0
Shutdown gracefully stops the server: it closes all listeners so no new connections are accepted, then polls until active connections drain or ctx is done. If ctx expires first, Shutdown returns ctx.Err() with connections still running; call Close to force them down.
type SlogLogger ¶ added in v1.0.0
type SlogLogger struct {
// contains filtered or unexported fields
}
SlogLogger adapts a structured *slog.Logger to the Logger interface. Messages are emitted at Info and Error levels on the wrapped logger.
func NewSlogLogger ¶ added in v1.0.0
func NewSlogLogger(l *slog.Logger) *SlogLogger
NewSlogLogger wraps a *slog.Logger into a server Logger. Passing nil uses slog.Default().
func (*SlogLogger) Errorf ¶ added in v1.0.0
func (sf *SlogLogger) Errorf(format string, args ...any)
Errorf implements Logger.
func (*SlogLogger) Infof ¶ added in v1.0.0
func (sf *SlogLogger) Infof(format string, args ...any)
Infof implements Logger.