Documentation
¶
Overview ¶
Package pep implements the paired fixed-egress performance-enhancing proxy.
Index ¶
- func ListenLocal(ctx context.Context, address string) (net.Listener, error)
- func NewAggregateBudget(totalBytesPerSec, reserveBytesPerSec uint64) *limiter.Budget
- type Client
- func (c *Client) MemoryStats() MemoryStats
- func (c *Client) Metrics() *metrics.Registry
- func (c *Client) Probe(ctx context.Context) (ProbeResult, error)
- func (c *Client) Serve(ctx context.Context) error
- func (c *Client) ServeListener(ctx context.Context, listener net.Listener) error
- func (c *Client) UpdateCredentials(updated identity.ClientCredentials) error
- type ClientConfig
- type CongestionControlKind
- type DestinationPolicy
- type FlowStats
- type LaneStats
- type MemoryLimits
- type MemoryStats
- type ProbeResult
- type Server
- func (s *Server) MaxObservedLanes() int
- func (s *Server) Metrics() *metrics.Registry
- func (s *Server) Serve(ctx context.Context) error
- func (s *Server) ServeListener(ctx context.Context, listener net.Listener) error
- func (s *Server) ServePacketConn(ctx context.Context, packetConn net.PacketConn) error
- type ServerConfig
- type SessionLimit
- type TransportKind
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ListenLocal ¶ added in v0.1.1
ListenLocal binds a local SOCKS5 listener. Serve and any caller which binds ahead of ServeListener share it so both get identical socket options.
func NewAggregateBudget ¶ added in v0.1.1
NewAggregateBudget builds one byte budget several clients can share, so a process running many clients paces to the configured total instead of offering that total once per client. A zero rate means unpaced.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
func NewClient ¶
func NewClient(cfg ClientConfig) (*Client, error)
func (*Client) MemoryStats ¶
func (c *Client) MemoryStats() MemoryStats
func (*Client) Probe ¶
func (c *Client) Probe(ctx context.Context) (ProbeResult, error)
Probe verifies that the configured provider accepts this device identity. It deliberately opens no destination. After mutual TLS it sends a bounded, intentionally invalid lane-join control frame and requires the protocol reset defined for that request. That round trip matters with TLS 1.3: a client can briefly consider its handshake complete before it observes the server rejecting a revoked certificate.
func (*Client) ServeListener ¶
ServeListener is primarily useful for tests and service managers which provide an already-bound socket. The listener is closed when the context is cancelled or the method returns.
func (*Client) UpdateCredentials ¶
func (c *Client) UpdateCredentials(updated identity.ClientCredentials) error
UpdateCredentials installs a renewed certificate for future handshakes. Trust domain, account, device, and public key are immutable: changing any of them requires importing a new profile and constructing a new client.
type ClientConfig ¶
type ClientConfig struct {
ListenAddr string
RemoteAddr string
LocalAddress string
// SocketControl is invoked after an outer socket is created and before it
// is bound or connected. Mobile VPN clients use it to exempt Queqiao's own
// TCP and UDP sockets from the virtual interface. A failure aborts the dial;
// silently continuing would route the tunnel through itself.
SocketControl func(network, address string, conn syscall.RawConn) error
// SOCKSAuth optionally requires RFC 1929 username/password on the local
// SOCKS5 listener. It is nil for the loopback-private listener used by the
// desktop agent and the mobile packet tunnel, and set when the listener is
// reachable by other applications on the same host, as in Android export
// mode where loopback is shared across every installed app.
SOCKSAuth *socks5.Credentials
Credentials identity.ClientCredentials
// Profile names the deployment this client is running in, and carries the
// policy that differs between deployments. The zero value is the supported
// access-link profile, so a caller that does not choose gets the behaviour
// the published measurements describe.
Profile profile.Profile
// FlowMetadataSocket is a local capture agent's lookup socket. Empty
// disables the lookup and is the default: a deployment without an agent
// behaves exactly as it did before this existed.
FlowMetadataSocket string
// FlowMetadataTimeout bounds one lookup. It runs on the accept path, so an
// agent that has wedged costs a flow a millisecond rather than its
// handshake.
FlowMetadataTimeout time.Duration
ChunkSize int
DialTimeout time.Duration
HandshakeTimeout time.Duration
FlowIdleTimeout time.Duration
FlowMaxLifetime time.Duration
MaxSessions int
// SessionLimit optionally shares admission across several clients in one
// process. Nil gives this client its own MaxSessions-sized limit.
SessionLimit *SessionLimit
// Budget optionally shares the aggregate byte budget across several
// clients in one process. Nil derives a private budget from
// AggregateBytesPerSec, which paces this client alone; a multi-provider
// process must share one budget or it offers the configured total once
// per provider.
Budget *limiter.Budget
// MaxPendingOpens bounds flows that are still establishing their remote
// transport. Keeping this separate from MaxSessions prevents a failed
// endpoint and its retries from occupying every healthy-flow slot.
MaxPendingOpens int
Transport TransportKind
// TCPFallbackLanes is the number of independent TLS/TCP connections used
// for a classified bulk flow. Values above one never affect QUIC.
TCPFallbackLanes int
// EnableQUICPool keeps one persistent QUIC connection for initial and
// control streams, and is what makes opening a flow cost nothing.
//
// Without it every flow dials its own connection, and so pays a handshake
// and a congestion ramp from the initial window before it carries a byte.
// Measured live on a 38% erasure path, a small flow cost 0.64 s, 1.11 s and
// 14.77 s on three attempts unpooled -- the last being a handshake that
// lost packets -- against 0.302, 0.292 and 0.300 pooled, which is one round
// trip and nothing else.
//
// It was opt-in because bulk on a pooled connection to a Reno peer measured
// worse than an independent lane. That reason has gone: the peer runs the
// erasure controller, the scheduler already moves classified bulk off the
// pooled connection onto lanes of its own, and bulk measured the same
// either way (0.85-1.15 MB/s pooled against 0.86-1.02 unpooled).
EnableQUICPool bool
// WaitForOpenAcknowledgement makes a flow wait for OPEN_OK before telling
// the application its connection is up. It is off by default, so a flow on
// a connection that is already established costs no round trips at all.
//
// Waiting costs exactly one round trip per flow, and an application opens
// a flow far more often than it opens a connection. Measured across an
// emulated 300 ms path, a first flow costs 922 ms -- a QUIC handshake, an
// authentication exchange and an open -- and every flow after it cost 306
// ms, which is one round trip of pure waiting on a pool that was already
// up. That is the cost this removes: request bytes now leave with the open
// rather than a round trip behind it.
//
// What is given up is the ability to answer SOCKS with a precise failure.
// The flow reader still validates the eventual OPEN_OK and propagates a
// typed RESET, so an unreachable destination becomes a connection that
// opens and then closes rather than one that never opens. Set this when a
// caller needs the distinction more than it needs the round trip.
WaitForOpenAcknowledgement bool
// UDPOnStream keeps SOCKS UDP packets on the lane's control stream even
// where the QUIC connection negotiated datagrams. It is the control for
// measuring the datagram substrate against the one it replaced, and both
// endpoints must be set the same way for the comparison to mean anything.
UDPOnStream bool
Congestion CongestionControlKind
BrutalBytesPerSec uint64
AdaptiveMinBytesSec uint64
AdaptiveMaxBytesSec uint64
AggregateBytesPerSec uint64
InteractiveReserveBytesPerSec uint64
// StreamReceiveWindow and ConnectionReceiveWindow override the QUIC
// receive windows. Zero selects the defaults, which match TUIC.
StreamReceiveWindow uint64
ConnectionReceiveWindow uint64
// Maximum windows disable quic-go's otherwise large receive-window growth.
// Zero keeps the high-throughput defaults. Resource-constrained clients set
// initial and maximum to the same bounded values.
MaxStreamReceiveWindow uint64
MaxConnectionReceiveWindow uint64
MaxIncomingStreams int64
// MemoryLimits is required by resource-constrained clients. Nil retains
// the throughput-oriented defaults used by servers and desktop clients.
MemoryLimits *MemoryLimits
Metrics *metrics.Registry
// FallbackDelay is when AUTO starts connecting its warm-standby TCP
// candidate. It is not a deadline for QUIC and not a transport-selection
// race.
FallbackDelay time.Duration
// FallbackGrace is how long a ready TCP standby waits for QUIC. Expiry may
// serve the current flow over TCP, but it is neutral UDP evidence. With a
// pool, the QUIC attempt continues in the background so later flows can
// return to the preferred transport.
FallbackGrace time.Duration
UDPFailureThreshold int
UDPCooldown time.Duration
Logger *slog.Logger
}
type CongestionControlKind ¶
type CongestionControlKind string
CongestionControlKind selects the QUIC sender.
Erasure is the default and the only one that should normally be chosen. Reno leaves the apNet quic-go default untouched and is the safe control. BBR is the original queqiao controller. BBRTUIC is a faithful Go port of TUIC's quinn-congestions BBR model. Adaptive is a conservative rate-estimating controller for unknown paths. Brutal is a fixed-rate mode for controlled experiments where the operator knows the per-lane budget.
const ( CongestionReno CongestionControlKind = "reno" CongestionBBR CongestionControlKind = "bbr" CongestionBBRTUIC CongestionControlKind = "bbr-tuic" CongestionAdaptive CongestionControlKind = "adaptive" CongestionBrutal CongestionControlKind = "brutal" // CongestionErasure is BBR corrected for a path that erases packets for // reasons unrelated to congestion. It is the right choice on a long-haul // path with a loss floor; on a clean path it reduces to BBR, because the // floor it measures is zero and the correction it applies is one. CongestionErasure CongestionControlKind = "erasure" )
type DestinationPolicy ¶
func (DestinationPolicy) DialContext ¶
func (DestinationPolicy) ResolveUDPAddr ¶
func (p DestinationPolicy) ResolveUDPAddr(ctx context.Context, destination string) ([]*net.UDPAddr, error)
ResolveUDPAddr validates and resolves a destination using exactly the same public-address policy as TCP CONNECT. It deliberately returns a concrete address: the server performs DNS resolution at the US egress and does not let the client influence a later DNS rebinding or private-address hop.
type FlowStats ¶
type FlowStats struct {
Started time.Time
Ended time.Time
BytesSent uint64
BytesRead uint64
// LaneBytes records payload bytes carried by each outer lane. It is
// intentionally optional so one-lane callers can ignore it, while
// benchmarks and operators can verify actual striping rather than merely
// counting successful lane handshakes.
LaneBytes map[uint64]LaneStats
}
type LaneStats ¶
type LaneStats struct {
Kind TransportKind
Sent uint64
Received uint64
}
type MemoryLimits ¶
type MemoryLimits struct {
// SendBudgetBytes and ReceiveBudgetBytes are shared by all flows. Send
// reservations block source reads; receive reservations fail only the flow
// that cannot retain an out-of-order frame, avoiding a cross-lane deadlock.
SendBudgetBytes int64
ReceiveBudgetBytes int64
MaxFlowSendBytes int
MaxFlowReceiveBytes uint64
MaxFlowOutstanding int
MaxFlowReceiveFrames int
EventQueueFrames int
LaneWriteQueueFrames int
LaneInteractiveReserve int
FrameReadBufferBytes int
MaxUDPPacketBytes int
MaxBulkConnections int
}
MemoryLimits turns the transport's multiplicative per-flow buffering into fixed endpoint budgets. A nil *MemoryLimits keeps the throughput-oriented server defaults. Mobile clients provide an explicit profile.
type MemoryStats ¶
type MemoryStats struct {
Send memlimit.Snapshot `json:"send"`
Receive memlimit.Snapshot `json:"receive"`
}
MemoryStats exposes exact retained-payload accounting. It deliberately does not claim to be whole-process RSS; platform and transport runtimes also own bounded buffers outside these budgets.
type ProbeResult ¶
type ProbeResult struct {
Transport TransportKind
Latency time.Duration
}
ProbeResult describes one authenticated provider connection attempt. Latency includes name resolution, transport establishment, mutual TLS, certificate authorization, and Queqiao ALPN negotiation.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
func NewServer ¶
func NewServer(cfg ServerConfig) (*Server, error)
func (*Server) MaxObservedLanes ¶
MaxObservedLanes reports the largest number of lanes attached to any flow since this server instance started. It is safe for benchmark instrumentation and does not expose session IDs or destination metadata.
func (*Server) ServeListener ¶
ServeListener runs the authenticated server on an already-bound listener. This also supports socket activation and deterministic integration tests.
func (*Server) ServePacketConn ¶
ServePacketConn runs the QUIC listener on an already-bound UDP socket.
type ServerConfig ¶
type ServerConfig struct {
// Profile names the deployment this gateway serves; see internal/profile.
// The zero value is the supported access-link profile.
Profile profile.Profile
ListenAddr string
Credentials identity.ServerCredentials
Enrollment *identity.EnrollmentService
ChunkSize int
HandshakeTimeout time.Duration
FlowIdleTimeout time.Duration
FlowMaxLifetime time.Duration
MaxSessions int
DestinationPolicy DestinationPolicy
EnableTCP bool
EnableQUIC bool
// TCPFallbackLanes is the admission ceiling for one negotiated TCP-only
// flow. The client chooses the active target; keeping the server ceiling at
// 16 lets operators compare 8 and 16 without changing the gateway.
TCPFallbackLanes int
// TCPCongestion selects the Linux kernel congestion controller inherited by
// accepted fallback sockets. "system" leaves the host default untouched.
TCPCongestion string
Congestion CongestionControlKind
BrutalBytesPerSec uint64
AdaptiveMinBytesSec uint64
AdaptiveMaxBytesSec uint64
AggregateBytesPerSec uint64
InteractiveReserveBytesPerSec uint64
// StreamReceiveWindow and ConnectionReceiveWindow override the QUIC
// receive windows. Zero selects the defaults, which match TUIC.
StreamReceiveWindow uint64
ConnectionReceiveWindow uint64
Metrics *metrics.Registry
Logger *slog.Logger
// UDPOnStream keeps SOCKS UDP packets on the lane's control stream even
// where the QUIC connection negotiated datagrams. See the client's field:
// it is a measurement control, and both endpoints must agree for the
// comparison to mean anything.
UDPOnStream bool
// contains filtered or unexported fields
}
type SessionLimit ¶ added in v0.1.1
type SessionLimit struct {
// contains filtered or unexported fields
}
SessionLimit bounds concurrent local SOCKS sessions across one or more clients. Admission is deliberately non-blocking so an overloaded listener can reject promptly instead of accumulating unauthenticated local sockets.
A limit may hold a private reservation as well as a share of a pool common to every client. The reservation is what keeps a quiet provider able to admit new flows while a busy sibling holds most of the common pool: a failover target which cannot accept a session is not a failover target.
func NewSessionLimit ¶ added in v0.1.1
func NewSessionLimit(max int) (*SessionLimit, error)
func NewSharedSessionLimits ¶ added in v0.1.1
func NewSharedSessionLimits(max, clients int) ([]*SessionLimit, error)
NewSharedSessionLimits divides max across clients so their combined admission never exceeds max while each client keeps a private reservation. Half the budget is reserved in equal shares and half stays common, so an idle provider can still burst into capacity its siblings are not using. When max is too small to reserve a slot per client the whole budget stays common.
func (*SessionLimit) Reserved ¶ added in v0.1.1
func (l *SessionLimit) Reserved() int
Reserved reports the slots this limit holds for its own client alone.
type TransportKind ¶
type TransportKind string
const ( TransportTCP TransportKind = "tcp" TransportQUIC TransportKind = "quic" TransportAuto TransportKind = "auto" )
Source Files
¶
- acktrack.go
- authorizationwatch.go
- client.go
- codedlane.go
- conntelemetry.go
- destination.go
- doc.go
- enrollmentlog.go
- flow.go
- frameconn.go
- laneadmission.go
- lanetrace.go
- memory.go
- mpflow.go
- probe.go
- random.go
- recordlimiter.go
- server.go
- sockerr_other.go
- stripedsend.go
- tcp_congestion.go
- tcp_congestion_linux.go
- transport.go
- udp.go
- udprelay.go
- uplink.go