Help us shape the future of Go! Take the 2026 Go Developer Survey

meek

package
v0.0.168 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package meek implements a domain-fronted meek client: chunked TCP-over-HTTPS, session-keyed by a per-Conn random ID sent in X-Session-Id. The wire format is the meek-v1 polling scheme as used by Psiphon and Lantern.

Each Conn maintains a single polling goroutine that POSTs to the meek server every PollIntervalMs, batching outbound bytes from Write into the request body and feeding the response body to readers via Read. The server is expected to be a meek endpoint behind any front the client dials — typically a Lantern-operated /meek/ endpoint reachable through Akamai or CloudFront via the inner Host.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewInbound

func NewInbound(
	ctx context.Context,
	router adapter.Router,
	logger log.ContextLogger,
	tag string,
	options option.MeekInboundOptions,
) (adapter.Inbound, error)

NewInbound constructs a meek inbound adapter.

func NewOutbound

func NewOutbound(
	ctx context.Context,
	router adapter.Router,
	logger log.ContextLogger,
	tag string,
	options option.MeekOutboundOptions,
) (adapter.Outbound, error)

NewOutbound constructs a meek outbound. Returns an error if no fronts or no URL are configured — without one, the outbound has nothing to dial.

func RegisterInbound

func RegisterInbound(registry *inbound.Registry)

RegisterInbound registers the meek inbound adapter with the given registry.

func RegisterOutbound

func RegisterOutbound(registry *outbound.Registry)

RegisterOutbound registers the meek outbound adapter.

Types

type Config

type Config struct {
	URL          string
	InnerHost    string
	ExtraHeaders map[string]string
	HTTPClient   *http.Client
	PollInterval time.Duration
	MaxBodyBytes int
	SessionIDLen int
	ReadTimeout  time.Duration
	// MaxWriteBufBytes caps the unsent Write backlog. Write blocks once
	// the buffer reaches this size and resumes as the poll loop drains
	// it, so a sender outpacing a slow front applies backpressure
	// instead of growing memory without bound.
	MaxWriteBufBytes int
	// MaxPollRetries is how many times a failed poll is retried (with backoff)
	// before the session is torn down. <=0 uses defaultMaxPollRetries. Retries
	// are made safe by the per-poll X-Meek-Seq the server dedupes.
	MaxPollRetries int
}

Config is the runtime configuration for a meek Conn.

type Conn

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

Conn is a net.Conn that tunnels through a meek server.

func Dial

func Dial(ctx context.Context, cfg Config) (*Conn, error)

Dial opens a meek session. The supplied HTTP client must be configured so its TLS DialContext targets a working front — typically the radiance fronted/scanner package's output composed with the standard fronted dialer.

func (*Conn) Close

func (c *Conn) Close() error

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

func (*Conn) Read

func (c *Conn) Read(p []byte) (int, error)

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline arranges for a parked Read to wake when t elapses. readCond.Wait has no native timeout, so without an active signal a Read would park past the deadline until data, close, or a new deadline arrived. A zero t clears the deadline.

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

SetWriteDeadline arranges for a Write blocked on a full backlog to wake when t elapses (mirrors SetReadDeadline): without an active signal the writeCond.Wait would park past the deadline if the front is hung and the poll loop never drains. A zero t clears the deadline.

func (*Conn) Write

func (c *Conn) Write(p []byte) (int, error)

type Inbound

type Inbound struct {
	inbound.Adapter
	// contains filtered or unexported fields
}

Inbound is the sing-box inbound adapter for a meek server. It serves the meek-v1 HTTP polling protocol (plain HTTP — a CDN/Caddy terminates TLS and fronting in front) and routes each tunneled session through sing-box.

The bundled meek outbound opens every session with a SOCKS5 CONNECT, so the inbound runs a tiny in-process SOCKS5 acceptor on loopback as the meek server's upstream: it terminates the CONNECT, extracts the destination, and hands the post-CONNECT stream to the router. This replaces the external SOCKS5 proxy (microsocks) that the standalone cmd/meek-server relies on, so the data plane is native sing-box (routing rules, the configured outbound, metrics all apply).

func (*Inbound) Close

func (i *Inbound) Close() error

Close stops the HTTP server, the meek server (and its sessions), the loopback acceptor, and the sing-box listener.

func (*Inbound) Start

func (i *Inbound) Start(stage adapter.StartStage) error

Start serves the meek HTTP endpoint and the loopback SOCKS5 acceptor.

type Outbound

type Outbound struct {
	outbound.Adapter
	// contains filtered or unexported fields
}

Outbound is the sing-box outbound adapter wrapping the meek client.

func (*Outbound) Close

func (o *Outbound) Close() error

func (*Outbound) DialContext

func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error)

DialContext opens a meek-tunneled TCP connection to destination.

sing-box treats this as a terminal outbound and writes the application stream straight into the returned conn, so the destination must be conveyed to the meek server's upstream before we hand the conn back. That upstream is a SOCKS5 proxy (microsocks in the standard deployment), so we run a SOCKS5 CONNECT to destination over the tunnel first; without it the upstream would read the application's opening bytes as a malformed SOCKS handshake and the connection would fail.

func (*Outbound) ListenPacket

func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error)

ListenPacket is unimplemented — meek is a TCP-stream-shaped transport.

func (*Outbound) Network

func (o *Outbound) Network() []string

type Server

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

Server is an http.Handler implementing the meek-v1 protocol.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer constructs a Server and starts the session reaper goroutine. Call Close to stop the reaper and tear down all sessions.

func (*Server) Close

func (s *Server) Close() error

Close stops the reaper and closes every active upstream connection. Idempotent.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles a POST from a meek client. Non-POST requests get 405; missing X-Session-Id gets 400.

func (*Server) SessionCount

func (s *Server) SessionCount() int

SessionCount is exposed for ops / metrics.

type ServerConfig

type ServerConfig struct {
	// Upstream is dialed for each new session and gets the bytes the
	// client posts; bytes from the upstream flow back as response
	// bodies. The server pipes bytes verbatim and is agnostic to the
	// upstream protocol, but the bundled meek outbound opens each session
	// with a SOCKS5 CONNECT, so a SOCKS5 proxy on the same host
	// (e.g. microsocks at "127.0.0.1:1080") is the expected deployment.
	Upstream string

	// MaxBodyBytes caps both the request-body the server accepts (larger
	// POSTs get 413) and the response-body it returns per POST. Default
	// 256 KiB (matches the client's default).
	MaxBodyBytes int

	// ResponseHoldoff is how long the server waits for upstream bytes
	// before responding with whatever it has (possibly empty).
	// Too small: many empty responses, idle CPU. Too large: high
	// client-perceived latency on the upstream-quiet path. Default
	// 50 ms.
	ResponseHoldoff time.Duration

	// SessionIdleTimeout is how long a session may go without a POST
	// before the reaper drops it. Should be at least 2-3x the client's
	// expected PollInterval to handle network blips. Default 5 min.
	SessionIdleTimeout time.Duration

	// Dialer optionally overrides net.Dial for upstream connections.
	Dialer func(network, address string) (net.Conn, error)

	// AuthToken, when non-empty, is a shared secret every request must
	// present in the X-Meek-Auth header. Without it the server is an
	// open relay into Upstream — anyone who reaches the endpoint can
	// create sessions and tunnel arbitrary traffic — so production
	// deployments on a public/fronted hostname MUST set it. Empty
	// disables the check (intended only for local tests).
	AuthToken string

	Logger *slog.Logger
}

ServerConfig configures a Server.

Jump to

Keyboard shortcuts

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