tcp

package
v0.67.3 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2026 License: BSD-3-Clause, AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// DefaultDrainTimeout is the default grace period for in-flight relay
	// connections to finish during shutdown.
	DefaultDrainTimeout = 30 * time.Second
	// DefaultMaxRelayConns is the default cap on concurrent TCP relay connections per router.
	DefaultMaxRelayConns = 4096
)
View Source
const DefaultIdleTimeout = 5 * time.Minute

DefaultIdleTimeout is the default idle timeout for TCP relay connections. A zero value disables idle timeout checking.

Variables

This section is empty.

Functions

func PeekClientHello

func PeekClientHello(conn net.Conn) (sni string, wrapped net.Conn, err error)

PeekClientHello reads the TLS ClientHello from conn, extracts the SNI server name, and returns a wrapped connection that replays the peeked bytes transparently. If the data is not a valid TLS ClientHello or contains no SNI extension, sni is empty and err is nil.

ECH/ESNI: When the client uses Encrypted Client Hello (TLS 1.3), the real server name is encrypted inside the encrypted_client_hello extension. This parser only reads the cleartext server_name extension (type 0x0000), so ECH connections return sni="" and are routed through the fallback path (or HTTP channel), which is the correct behavior for a transparent proxy that does not terminate TLS.

func Relay

func Relay(ctx context.Context, logger *log.Entry, src, dst net.Conn, idleTimeout time.Duration) (srcToDst, dstToSrc int64)

Relay copies data bidirectionally between src and dst until both sides are done or the context is canceled. When idleTimeout is non-zero, each direction's read is deadline-guarded; if no data flows within the timeout the connection is torn down. When one direction finishes, it half-closes the write side of the destination (if supported) to signal EOF, allowing the other direction to drain gracefully before the full connection teardown.

Types

type DialResolver

type DialResolver func(accountID types.AccountID) (types.DialContextFunc, error)

DialResolver returns a DialContextFunc for the given account.

type RelayObserver

type RelayObserver interface {
	TCPRelayStarted(accountID types.AccountID)
	TCPRelayEnded(accountID types.AccountID, duration time.Duration, srcToDst, dstToSrc int64)
	TCPRelayDialError(accountID types.AccountID)
	TCPRelayRejected(accountID types.AccountID)
}

RelayObserver receives callbacks for TCP relay lifecycle events. All methods must be safe for concurrent use.

type Route

type Route struct {
	Type      RouteType
	AccountID types.AccountID
	ServiceID types.ServiceID
	// Domain is the service's configured domain, used for access log entries.
	Domain string
	// Protocol is the frontend protocol (tcp, tls), used for access log entries.
	Protocol accesslog.Protocol
	// Target is the backend address for TCP relay (e.g. "10.0.0.5:5432").
	Target string
	// ProxyProtocol enables sending a PROXY protocol v2 header to the backend.
	ProxyProtocol bool
	// DialTimeout overrides the default dial timeout for this route.
	// Zero uses defaultDialTimeout.
	DialTimeout time.Duration
	// SessionIdleTimeout overrides the default idle timeout for relay connections.
	// Zero uses DefaultIdleTimeout.
	SessionIdleTimeout time.Duration
	// Filter holds connection-level IP/geo restrictions. Nil means no restrictions.
	Filter *restrict.Filter
}

Route describes where a connection for a given SNI should be sent.

type RouteType

type RouteType int

RouteType specifies how a connection should be handled.

const (
	// RouteHTTP routes the connection through the HTTP reverse proxy.
	RouteHTTP RouteType = iota
	// RouteTCP relays the connection directly to the backend (TLS passthrough).
	RouteTCP
)

type Router

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

Router accepts raw TCP connections on a shared listener, peeks at the TLS ClientHello to extract the SNI, and routes the connection to either the HTTP reverse proxy or a direct TCP relay.

func NewPortRouter

func NewPortRouter(logger *log.Logger, dialResolve DialResolver) *Router

NewPortRouter creates a Router for a dedicated port without an HTTP channel. Connections that don't match any SNI route fall through to the fallback relay (if set) or are closed.

func NewRouter

func NewRouter(logger *log.Logger, dialResolve DialResolver, addr net.Addr) *Router

NewRouter creates a new SNI-based connection router.

func (*Router) AddRoute

func (r *Router) AddRoute(host SNIHost, route Route)

AddRoute registers an SNI route. Multiple routes for the same host are stored and resolved by priority at lookup time (HTTP > TCP). Empty host is ignored to prevent conflicts with ECH/ESNI fallback.

func (*Router) Drain

func (r *Router) Drain(timeout time.Duration) bool

Drain prevents new relay connections from starting and waits for all in-flight connection handlers and active relays to finish, up to the given timeout. Returns true if all completed, false on timeout.

func (*Router) HTTPListener

func (r *Router) HTTPListener() net.Listener

HTTPListener returns a net.Listener that yields connections routed to the HTTP handler. Use this with http.Server.ServeTLS.

func (*Router) IsEmpty

func (r *Router) IsEmpty() bool

IsEmpty returns true when the router has no SNI routes and no fallback.

func (*Router) RemoveFallback

func (r *Router) RemoveFallback(svcID types.ServiceID)

RemoveFallback clears the catch-all fallback route and closes any active relay connections for the given service.

func (*Router) RemoveRoute

func (r *Router) RemoveRoute(host SNIHost, svcID types.ServiceID)

RemoveRoute removes the route for the given host and service ID. Active relay connections for the service are closed immediately. If other routes remain for the host, they are preserved.

func (*Router) Serve

func (r *Router) Serve(ctx context.Context, ln net.Listener) error

Serve accepts connections from ln and routes them based on SNI. It blocks until ctx is canceled or ln is closed, then drains active relay connections up to DefaultDrainTimeout.

func (*Router) SetAccessLogger

func (r *Router) SetAccessLogger(l l4Logger)

SetAccessLogger sets the L4 access logger. Must be called before Serve.

func (*Router) SetFallback

func (r *Router) SetFallback(route Route)

SetFallback registers a catch-all route for connections that don't match any SNI route. On a port router this handles plain TCP relay; on the main router it takes priority over the HTTP channel.

func (*Router) SetGeo

func (r *Router) SetGeo(geo restrict.GeoResolver)

SetGeo sets the geolocation lookup used for country-based restrictions.

func (*Router) SetObserver

func (r *Router) SetObserver(obs RelayObserver)

SetObserver sets the relay lifecycle observer. Must be called before Serve.

type SNIHost

type SNIHost string

SNIHost is a typed key for SNI hostname lookups.

Jump to

Keyboard shortcuts

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