gproxy

package
v0.1.9 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package gproxy implements a gnet-based event-driven MTProxy server.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckFrameSize added in v0.1.8

func CheckFrameSize(size int) bool

CheckFrameSize checks if a frame size indicates desync. Returns true if the frame size is abnormally large (likely desync).

func IsUnixSocket added in v0.1.4

func IsUnixSocket(addr string) bool

IsUnixSocket returns true if the bind address is a Unix socket.

func Run

func Run(cfg *Config, logger Logger) (shutdown func(), errCh <-chan error)

Run starts the proxy with graceful shutdown support using gnet. Returns a shutdown function that can be called to stop the server.

func Zeroize added in v0.1.8

func Zeroize(b []byte)

Zeroize overwrites a byte slice with zeros. This is used for secure cleanup of sensitive data like session IDs.

Note: Go's compiler may optimize away zeroing of "dead" variables. For maximum security, call this before the variable goes out of scope while it's still reachable.

func ZeroizeArray32 added in v0.1.8

func ZeroizeArray32(arr *[32]byte)

ZeroizeArray32 zeros a 32-byte array in place.

Types

type BufferPool added in v0.1.8

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

BufferPool is a sync.Pool wrapper for reusable byte buffers.

func NewBufferPool added in v0.1.8

func NewBufferPool(size int) *BufferPool

NewBufferPool creates a new buffer pool with the given buffer size.

func (*BufferPool) Get added in v0.1.8

func (bp *BufferPool) Get() *[]byte

Get retrieves a buffer from the pool. The returned buffer may contain stale data - caller should slice or overwrite.

func (*BufferPool) Put added in v0.1.8

func (bp *BufferPool) Put(buf *[]byte)

Put returns a buffer to the pool. The buffer should not be used after calling Put.

type Config

type Config struct {
	// Secrets is the list of allowed proxy secrets.
	Secrets []Secret
	Host    string // Default SNI hostname (from first secret)

	// Network
	BindAddr string

	// TLS Fronting
	MaskHost           string // Domain to mimic (SNI validation, proxy links)
	MaskPort           int    // Default port
	FetchRealCert      bool
	SpliceUnrecognized bool
	CertRefreshHours   int

	// Certificate fetching (where to connect to get real cert)
	// Defaults to MaskHost:MaskPort if not set
	CertHost string
	CertPort int

	// Splice target (where to forward unrecognized clients)
	// Defaults to MaskHost:MaskPort if not set
	SpliceHost          string
	SplicePort          int
	SpliceProxyProtocol int // 0 = off, 1 = v1 (text), 2 = v2 (binary)

	// Performance
	IPPreference      dc.IPPreference
	IdleTimeout       time.Duration
	TimeSkewTolerance time.Duration

	// Upstream (DC connection)
	Socks5Addr string // SOCKS5 proxy for DC connections (e.g., "127.0.0.1:1080")

	// Incoming connection handling
	ProxyProtocol       bool // Accept incoming PROXY protocol headers
	MaxConnectionsPerIP int  // Per IP+secret limit, 0 = unlimited

	// Backpressure
	MaxWriteBuffer int // Max pending bytes per connection before closing (0 = 4MB default)

	// gnet-specific
	Multicore    bool // Use multiple event loops
	ReusePort    bool // Enable SO_REUSEPORT
	LockOSThread bool // Lock goroutines to OS threads
	NumEventLoop int  // Number of event loops (0 = auto)
}

Config configures the gnet proxy server.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns sensible defaults.

type ConnContext

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

ConnContext holds per-connection state for the gnet event handler.

func NewConnContext

func NewConnContext() *ConnContext

NewConnContext creates a new connection context.

func (*ConnContext) Cleanup added in v0.1.8

func (c *ConnContext) Cleanup()

Cleanup zeros sensitive data in the connection context. Should be called when the connection is closed. Note: cipher.Stream internal state cannot be zeroed (opaque Go types).

func (*ConnContext) DCID added in v0.1.8

func (c *ConnContext) DCID() int

DCID returns the DC ID this connection is using (0 if not yet determined).

func (*ConnContext) ID added in v0.1.4

func (c *ConnContext) ID() uint64

ID returns the connection ID.

func (*ConnContext) LogPrefix added in v0.1.4

func (c *ConnContext) LogPrefix() string

LogPrefix returns a log prefix like "#123" or "#123:user1".

func (*ConnContext) RealClientAddr added in v0.1.4

func (c *ConnContext) RealClientAddr(fallback net.Addr) net.Addr

RealClientAddr returns the real client address from PROXY protocol. Falls back to the provided gnet connection's remote address if not set.

func (*ConnContext) Relay

func (c *ConnContext) Relay() *RelayContext

Relay returns the relay context (lock-free, may be nil).

func (*ConnContext) SetRealClientAddr added in v0.1.4

func (c *ConnContext) SetRealClientAddr(addr net.Addr)

SetRealClientAddr sets the real client address from PROXY protocol.

func (*ConnContext) SetRelay

func (c *ConnContext) SetRelay(r *RelayContext)

SetRelay sets the relay context and transitions to relay state.

func (*ConnContext) SetSpliceConn added in v0.1.2

func (c *ConnContext) SetSpliceConn(conn net.Conn)

SetSpliceConn sets the splice connection.

func (*ConnContext) SetState

func (c *ConnContext) SetState(state ConnState)

SetState sets the connection state (lock-free).

func (*ConnContext) SpliceConn added in v0.1.2

func (c *ConnContext) SpliceConn() net.Conn

SpliceConn returns the splice connection (lock-free, may be nil).

func (*ConnContext) State

func (c *ConnContext) State() ConnState

State returns the current connection state (lock-free).

type ConnLimiter added in v0.1.4

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

ConnLimiter limits concurrent connections per IP+secret combination. Uses sharded maps and atomic counters for minimal contention.

func NewConnLimiter added in v0.1.4

func NewConnLimiter(maxConns int) *ConnLimiter

NewConnLimiter creates a new connection limiter. maxConns <= 0 disables limiting.

func (*ConnLimiter) ActiveConnections added in v0.1.4

func (l *ConnLimiter) ActiveConnections() int64

ActiveConnections returns the total number of active connections being tracked. This is O(n) and should only be used for metrics, not in hot path.

func (*ConnLimiter) Release added in v0.1.4

func (l *ConnLimiter) Release(key string)

Release releases a connection slot. key must be the value returned by TryAcquire.

func (*ConnLimiter) TryAcquire added in v0.1.4

func (l *ConnLimiter) TryAcquire(ip net.IP, secret []byte) (key string, ok bool)

TryAcquire attempts to acquire a connection slot for the given IP+secret. Returns the key (for Release) and success status. If maxConns is 0, always succeeds (limiting disabled).

type ConnState

type ConnState int32

ConnState represents the current state of a client connection.

const (
	StateReadProxyProto ConnState = iota // Need PROXY protocol header (optional)
	StateReadTLSHeader                   // Need 5 bytes for TLS record header
	StateReadTLSPayload                  // Need header.length bytes for payload
	StateReadO2Frame                     // Need 64 bytes for obfuscated2 frame
	StateDialingDC                       // Async dial in progress
	StateRelaying                        // Bidirectional relay active
	StateSplicing                        // Forward to mask host (invalid client)
	StateClosed                          // Connection is closing
)

func (ConnState) String

func (s ConnState) String() string

String returns the state name for debugging.

type DCConnContext added in v0.1.2

type DCConnContext struct {
	// Link back to client connection
	ClientConn gnet.Conn

	// Client context for state access
	ClientCtx *ConnContext

	// DC ciphers (proxy <-> DC)
	DCEncrypt cipher.Stream
	DCDecrypt cipher.Stream

	// Client ciphers (cached from relay context)
	ClientEncrypt cipher.Stream // encrypt TO client

	// Flow control: DC connection reference for wake mechanism
	DCConn gnet.Conn
}

DCConnContext holds per-DC-connection state.

type DesyncDetector added in v0.1.8

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

DesyncDetector tracks and reports protocol desynchronization events. Desync typically happens when crypto state diverges, causing decryption to produce garbage that looks like impossibly large frames.

func NewDesyncDetector added in v0.1.8

func NewDesyncDetector() *DesyncDetector

NewDesyncDetector creates a new desync detector.

func (*DesyncDetector) Report added in v0.1.8

func (d *DesyncDetector) Report(
	ctx *ConnContext,
	frameSize int,
	direction string,
	logger Logger,
) bool

Report reports a potential desync event. Returns true if this event was logged (not deduplicated). direction is "c2dc" (client to DC) or "dc2c" (DC to client).

type HotReloadConfig added in v0.1.8

type HotReloadConfig struct {
	ConfigPath string                          // Path to config file
	LoadConfig func() (*Config, string, error) // Config loader function
	Handler    *ProxyHandler
	Logger     Logger
	SetLogFn   func(level string) // Function to set log level
}

HotReloadConfig contains configuration for the hot reloader.

type HotReloader added in v0.1.8

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

HotReloader watches a config file and reloads hot fields on change. Supports both file watching (fsnotify) and SIGHUP.

func NewHotReloader added in v0.1.8

func NewHotReloader(cfg HotReloadConfig) *HotReloader

NewHotReloader creates a new hot reloader.

func (*HotReloader) Start added in v0.1.8

func (r *HotReloader) Start()

Start begins watching for config changes. Returns immediately; watching runs in background goroutines.

func (*HotReloader) Stop added in v0.1.8

func (r *HotReloader) Stop()

Stop stops the hot reloader.

type Logger

type Logger interface {
	Debug(format string, args ...any)
	Info(format string, args ...any)
	Warn(format string, args ...any)
	Error(format string, args ...any)
}

Logger interface for proxy logging.

type ProxyHandler

type ProxyHandler struct {
	gnet.BuiltinEventEngine
	// contains filtered or unexported fields
}

ProxyHandler implements gnet.EventHandler for the MTProxy server.

func NewProxyHandler

func NewProxyHandler(cfg *Config, logger Logger) *ProxyHandler

NewProxyHandler creates a new gnet proxy handler.

func RunWithHandler added in v0.1.8

func RunWithHandler(cfg *Config, logger Logger) (shutdown func(), handler *ProxyHandler, errCh <-chan error)

RunWithHandler starts the proxy and returns the handler for hot-reload. Returns a shutdown function, the handler (for hot-reload), and error channel.

func (*ProxyHandler) ApplyHotConfig added in v0.1.8

func (h *ProxyHandler) ApplyHotConfig(cfg *Config)

ApplyHotConfig applies hot-reloadable configuration changes. Only certain fields can be changed at runtime; others require restart. Hot-reloadable fields:

  • IdleTimeout: affects new connections only (existing keep their timeout)

Non-hot fields (require restart):

  • BindAddr, Secrets, MaskHost/Port, ProxyProtocol, MaxConnectionsPerIP

func (*ProxyHandler) OnBoot

func (h *ProxyHandler) OnBoot(eng gnet.Engine) gnet.Action

OnBoot is called when the gnet engine starts.

func (*ProxyHandler) OnClose

func (h *ProxyHandler) OnClose(c gnet.Conn, err error) gnet.Action

OnClose is called when a connection is closed.

func (*ProxyHandler) OnOpen

func (h *ProxyHandler) OnOpen(c gnet.Conn) ([]byte, gnet.Action)

OnOpen is called when a new connection is accepted.

func (*ProxyHandler) OnShutdown

func (h *ProxyHandler) OnShutdown(eng gnet.Engine)

OnShutdown is called when the gnet engine shuts down.

func (*ProxyHandler) OnTraffic

func (h *ProxyHandler) OnTraffic(c gnet.Conn) gnet.Action

OnTraffic is called when data is available to read.

type ProxyProtoResult added in v0.1.4

type ProxyProtoResult struct {
	SrcAddr   net.Addr // Source (client) address
	DstAddr   net.Addr // Destination (server) address
	HeaderLen int      // Total bytes consumed by header
	IsLocal   bool     // True if LOCAL command (health check)
}

ProxyProtoResult holds the parsed PROXY protocol header result.

func ParseProxyProtocol added in v0.1.4

func ParseProxyProtocol(data []byte) (*ProxyProtoResult, error)

ParseProxyProtocol attempts to parse a PROXY protocol v1 or v2 header. Returns nil if the data doesn't start with a valid PROXY protocol header. Returns error if header is malformed or incomplete.

type RelayContext

type RelayContext struct {
	// Client ciphers (client <-> proxy)
	Encryptor cipher.Stream // encrypt data TO client
	Decryptor cipher.Stream // decrypt data FROM client

	// DC connection and ciphers (proxy <-> DC)
	DCConn    gnet.Conn     // gnet connection to Telegram DC (enrolled in dcClient)
	DCEncrypt cipher.Stream // encrypt data TO DC
	DCDecrypt cipher.Stream // decrypt data FROM DC
}

RelayContext holds immutable relay state set once after handshake. Read without locking via atomic pointer.

type ReplayCache

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

ReplayCache detects replay attacks by tracking seen session IDs. Uses sharded expirable LRU caches for:

  • Proper LRU eviction (oldest entries removed first)
  • Automatic TTL expiration
  • Reduced lock contention (64 shards)

func NewReplayCache

func NewReplayCache(maxSize int, ttl time.Duration) *ReplayCache

NewReplayCache creates a new replay cache. maxSize is the total capacity across all shards. ttl is how long entries are kept before automatic expiration.

func (*ReplayCache) Len added in v0.1.8

func (c *ReplayCache) Len() int

Len returns the total number of entries across all shards.

func (*ReplayCache) Seen

func (c *ReplayCache) Seen(sessionID []byte) bool

Seen checks if the session ID was seen before and adds it if not. Returns true if this is a replay attack, false if new. This operation is atomic (check-and-add).

type Secret

type Secret struct {
	Name   string // User-friendly name for logging
	Key    []byte // 16-byte secret key
	Host   string // SNI hostname
	RawHex string // Original hex string for link generation
}

Secret represents a named proxy secret.

Jump to

Keyboard shortcuts

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