Add configurable TCP keepalive (keepalive, keepalive.idle,
keepalive.interval, keepalive.count) to all TCP-based transport types:
tls, mtls, mtcp, ws/wss, mws/mwss, http2, ssh, sshd listeners and
tls, mtls, mtcp, ws/wss, mws/mwss, ssh, sshd dialers.
For types that already use "keepalive" for an app-level protocol
(grpc listener/dialer, ws/mws dialers, ssh/sshd dialers), the TCP
keepalive parameters are exposed under the tcp.keepalive.* prefix to
avoid ambiguity.
Also extract shared helpers into internal/net/keepalive.go:
- WrapKeepaliveListener: applies KeepAliveConfig on every accepted TCPConn
- ApplyKeepalive: applies KeepAliveConfig to a single TCPConn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exposes TCP keepalive configuration via listener and dialer metadata:
keepalive: true
keepalive.idle: 30s
keepalive.interval: 10s
keepalive.count: 6
When enabled, the OS sends keepalive probes after the idle period and
tears down the socket if the remote does not respond. This causes any
blocked Read() on a dead connection to return promptly, releasing
goroutines and memory — covering both legs of a CONNECT tunnel (the
inbound client connection via the listener, and the outbound upstream
connection via the dialer).
This is the correct alternative to a hard application-level read
deadline (SetReadDeadline) for detecting dead connections, as it
distinguishes truly dead connections from legitimately idle ones.
Relates to: https://github.com/go-gost/x/issues/91
The 30s hardcoded readTimeout in Pipe() caused all CONNECT tunnel
connections to be hard-closed after 30s of inactivity, breaking
WebSocket and long-polling connections through the proxy.
Pipe() now accepts a WithReadTimeout(d) option. When d is 0 (the
default) no read deadline is set, relying on TCP keepalives or context
cancellation to detect dead connections instead.
The HTTP handler exposes this as the idleTimeout metadata key.
Fixes: https://github.com/go-gost/x/issues/91
- Return err instead of nil in SS TCP/UDP connector Init when
NewClientConfig fails, preventing nil pointer dereference in WrapConn
- Initialize tcpClient in UDP connector for UDP-over-TCP path
- Add decodeSIP002Auth to handle ss://BASE64(method:password)@host:port
URL format with RawURLEncoding and StdEncoding fallback
- Update buildServiceConfig and buildNodeConfig to decode SIP002 auth
for ss* schemes before falling back to standard userinfo parsing
- Support RawURLEncoding in parseAuthFromCmd with StdEncoding fallback
- Add tests for decodeSIP002Auth, parseAuthFromCmd, and integration
tests for buildNodeConfig/buildServiceConfig
- Add Header field to PHT Client and clientConn structs
- Support custom headers in authorize, push, and pull requests
- Add metadata parsing for header configuration as map[string]string
- Enables PHT usage with header-based authentication (e.g., Cloudflare Access)
Backwards compatible - headers are optional.
Implement UDP tunneling over HTTP/3 using HTTP Datagrams (RFC 9297):
- Add masque handler for server-side CONNECT-UDP
- Add masque connector and h3-masque dialer for client-side
- Add enableDatagrams option to HTTP/3 listener
- Add shared utilities for datagram connections and path parsing
Resource management and connection caching:
- Add deferred stream cleanup in connector on error paths
- Add IsClosed() and Close() methods to Client for proper session management
- Clean up stale cached clients in dialer before reuse
- Close underlying stream when DatagramConn is closed
- Move RequestStream opening from connector to dialer to enable dead
connection detection and cache invalidation (follows QUIC dialer pattern)
Extend MASQUE implementation to support TCP tunneling via standard HTTP/3
CONNECT method, in addition to existing UDP support via CONNECT-UDP:
- Add StreamConn type for TCP data transfer over HTTP/3 stream body
- Update handler to dispatch based on :protocol pseudo-header:
- "connect-udp" for UDP (RFC 9298)
- Empty/"HTTP/3.0" for TCP (RFC 9114)
- Add handleConnectTCP() using bidirectional stream relay
- Update connector to support both TCP and UDP networks
- Add connectTCP() for standard CONNECT requests
TCP uses :authority for target address and stream body for data.
UDP uses path template and HTTP/3 datagrams for data.
Implement UDP tunneling over HTTP/3 using HTTP Datagrams (RFC 9297):
- Add masque handler for server-side CONNECT-UDP
- Add masque connector and h3-masque dialer for client-side
- Add enableDatagrams option to HTTP/3 listener
- Add shared utilities for datagram connections and path parsing
Resource management and connection caching:
- Add deferred stream cleanup in connector on error paths
- Add IsClosed() and Close() methods to Client for proper session management
- Clean up stale cached clients in dialer before reuse
- Close underlying stream when DatagramConn is closed
- Move RequestStream opening from connector to dialer to enable dead
connection detection and cache invalidation (follows QUIC dialer pattern)