On Windows, icmp.ListenPacket("ip4:icmp", "0.0.0.0") does not reliably
deliver ICMP packets (golang/go#38427). Add a platform-specific
ListenPacket helper that binds to a discovered interface address and
enables SIO_RCVALL via WSAIoctl for promiscuous receive.
Fixesgo-gost/x#36
tokenTransport now delegates CloseIdleConnections to the underlying
*http.Transport so http.Client.CloseIdleConnections() works through
the wrapper. Three plugin Close() methods updated to unwrap via
HTTPClientTransport before calling CloseIdleConnections.
RoundTrip now short-circuits when caller already set Authorization,
avoiding an unnecessary req.Clone allocation on the pass-through path.
Pull node-resolution logic out of dial/dialTLS into pure resolveHTTPNode
and resolveTLSNode helpers. This separates node selection (bypass, hop,
fallback) from connection establishment, making both independently
testable. Add 21 new tests covering bypass, hop selection, nil-hop,
addr fallback, upgrade response type mismatch, websocket frames,
response body rewriting, and h2 preface validation.
- Use local readTimeout copy in HandleOptions instead of mutating shared
Sniffer.ReadTimeout, eliminating a data race under concurrent calls
- Close both connections in sniffingWebsocketFrame when one direction
errors, preventing indefinite goroutine blockage
- Add bounds check on PeerCertificates before indexing in terminateTLS
- Discard non-fatal ParseServerHello error instead of returning it after
successful xnet.Pipe
- Log res.Write errors in bypass/bad-gateway/connect-failure paths
- Add doc comments to all 15 exported symbols
Replace cidranger third-party dependency with a custom binary trie for
zero-allocation CIDR containment lookups. Migrate ipMatcher from
string-keyed map to netip.Addr for correct IPv4/IPv6 normalization.
Extract shared splitHostPort helper to eliminate repeated host:port
parsing boilerplate across all matchers. Add comprehensive benchmarks.
Normalize Only/Prefer values (ip4→ipv4, ip6→ipv6) so downstream
comparisons match correctly. Fix asymmetric fallback where caller
network=ip6 fell through to IPv4 but ip4 didn't fall through to IPv6
— both branches now check hard constraints (server.Only || callerPref)
only, allowing soft Prefer to fall back. Fix data race on cache item.ts
by reading it inside RLock. Fix Store mutating caller's dns.Msg by
copying before TTL override. Add singleflight dedup, semaphore-bounded
async refresh, DNS rcode error checking, and bump EDNS0 UDPSize to
4096. Add 25 tests.
matcher: fix IPv6 normalization via netip.ParseAddr, port-range overwrite
by switching to []*PortRange map, case-insensitive domain/host matching,
glob.MustCompile→Compile to avoid panic on invalid patterns.
plugin: guard nil *Options in NewGRPCConn and NewHTTPClient; add
HTTPClientTransport helper for idle-connection cleanup.
net/*: add doc comments for all exported symbols (no code changes).
Add 30 tests (matcher_test.go 22, plugin_test.go 8) covering all
matcher types, nil safety, case insensitivity, IPv6 normalization,
port ranges, and plugin option composition.
- entrypoint.go: guard ictx.RecorderObjectFromContext with nil checks on
ClientID and Redirect assignments
- io.go: fix CloseRead checking Writer instead of Reader, add Reader
fallback to CloseWrite, unwrap *readWriter/*readWriteCloser in
SetReadDeadline to reach underlying net.Conn
- docs: add package doc and exported symbol comments to internal/ctx
and internal/io
- Bump go-shadowsocks2 to v0.1.3 (new API symbols)
- Return error instead of nil when Target() is empty in TCP handler
- Reset wbuf unconditionally on write error to prevent unbounded growth
- Add nil guard on targetAddr before WriteTo to prevent panic
- Remove duplicate NewClientConfig call and dead ClientConfig literal
- Remove unused noDelay metadata field
- Fix buffer-size guard to catch negative values (len(b)==0 → bufSize<=0)
- Add address context to parse/session error messages
- Return errors from MasqueConn.Read/Write instead of silently
succeeding (prevents infinite busy-loops and silent data loss
if these methods are accidentally called).
- Set recorder Network field in protocol dispatch switch rather
than hardcoding "udp", so early errors don't misreport type.
- Clarify that DatagramConn context-ID handling only supports
context ID 0 (sufficient for CONNECT-UDP per RFC 9298).
Merge beezly/fix/configurable-pipe-timeout with conflict resolution
in pipe.go (PipeOption/WithReadTimeout functional options pattern).
Fix pipe_test.go: update 4 pipeHalf() calls to pass readTimeout arg
matching the new signature.
Fix setMark early-return conditions that were inverted relative to
Linux: on FreeBSD (SO_USER_COOKIE) and OpenBSD (SO_RTABLE), a
non-zero mark was short-circuited instead of applied, disabling
socket marking entirely.
Also fix GetClientIP to trim leading whitespace from X-Forwarded-For
entries (per RFC 7239), and fix Body.Read to subtract len(b) instead
of n from recordSize when a single read exceeds the remaining quota.
Add unit tests for internal/net/ (addr, dialer, http, ip, net, pipe,
transport, resolve, proxyproto, udp).
Pipe: remove context.WithCancel that caused premature ctx.Done()
before the second pipeHalf could return its error. Replace with a
completed counter that drains both errors even on cancellation.
Transport: increase error channel buffer from 1 to 2 to prevent
goroutine leak when both CopyBuffer goroutines complete.
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>
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
- 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)