Commit Graph

253 Commits

Author SHA1 Message Date
ginuerzh 7e9d14bb41 test(handler/router): add associate_test.go (handleAssociate, handlePacket, getRoute, getAddrforRoute, sdRenew) 2026-06-05 20:46:00 +08:00
ginuerzh ca83acc323 test(handler/router): add handler_test.go (NewHandler, Init, Handle, Close) 2026-06-05 20:46:00 +08:00
ginuerzh 901131d0ed test(handler/router): add conn_test.go (packetConn, lockWriter) 2026-06-05 20:46:00 +08:00
ginuerzh 105f7e32d0 test(handler/router): add observe_test.go (checkRateLimit, observeStats) 2026-06-05 20:46:00 +08:00
ginuerzh 32056092f5 test(handler/router): add router_test.go (Connector, Router, ConnectorPool, parseRouterID) 2026-06-05 20:46:00 +08:00
ginuerzh 9db0f07721 test(handler/router): add metadata_test.go for parseMetadata 2026-06-05 20:46:00 +08:00
ginuerzh b48ef7e363 test(handler/router): add helpers_test.go with mocks and test infrastructure 2026-06-05 20:46:00 +08:00
ginuerzh 5608b5fa67 fix(handler/router): add break to DelConnector after successful delete 2026-06-05 20:46:00 +08:00
ginuerzh ef83d839db refactor(handler/router): extract observe.go (observeStats, checkRateLimit) from handler.go 2026-06-05 20:46:00 +08:00
ginuerzh 31cf571a6a refactor(handler/router): extract conn.go (packetConn, lockWriter) from associate.go 2026-06-05 20:46:00 +08:00
ginuerzh a1fddedcc3 fix(handler/relay): remove remaining Chinese comments missed in conversion
Clean up 12 inline comments across bind.go, conn.go, connect.go,
entrypoint.go, handler.go that were still in Chinese.
2026-06-03 23:09:04 +08:00
ginuerzh d5fd62aa47 docs(handler/relay): convert all comments to English
Translate all Chinese comments in the relay handler package to English:
handler.go, connect.go, bind.go, forward.go, conn.go, entrypoint.go,
observe.go, metadata.go. All inline and doc comments are now in English.

Also set a persistent preference: all future code comments must be
written in English only.
2026-06-03 23:05:08 +08:00
ginuerzh 95874c53f5 fix: add status field to service list/detail APIs, unify observeStats retry pattern, fix router bugs
- api: add fillServiceStatus helper and call it from getServiceList/getService
  so status field appears in service list and detail API responses
- observeStats: unify retry pattern across all 9 handlers (http, http2, masque,
  relay, router, socks4, socks5, tungo, tunnel) — buffer events on failure,
  continue to skip fresh collection, clear on success; fix event-loss bug
  where interim events were dropped during retry cycles
- handler/router: check WriteTo/Write return errors in associate.go and
  entrypoint.go; fix DelConnector and ConnectorPool.Del using RLock instead
  of Lock (write under read lock); remove unused fields t and cancel
2026-06-03 22:12:08 +08:00
ginuerzh 29a5b16395 fix(handler/tunnel): respect user-supplied host in handleBind, add ingress conflict detection
The response address sent back to the tunnel client was unconditionally
set to the md5 hash of the tunnel ID. This meant the user's custom host
(e.g. "dash" from "dash:8081") was ignored — the client listened on
the hash instead.

Now the user-supplied host is used directly when:
1. A host is present in the bind address AND ingress is configured.
2. No other tunnel has already claimed that host in ingress
   (conflict check via GetRule).

Fall back to the md5 hash when no host is supplied, ingress is nil, or
the host conflicts with an existing ingress rule.

Also fixes indentation in the WriteTo error handling block (extra tab
removed).

Tests:
- TestHandleBind_CustomHost: response AddrFeature uses "dash", not hash
- TestHandleBind_CustomHostConflict: conflicting host falls back to hash
- fakeIngress enhanced with ruleByHost map for conflict simulation
2026-06-03 21:14:42 +08:00
ginuerzh 91920aa805 fix #866: SOCKS5 nil ptr TLSConfig in selector
Move SetDefaultTLSConfig before register(cfg) in loader.go so
ParseService can access it when building handlers. Also add a
defensive nil check in socks5 serverSelector.Select() for
MethodTLS to prevent future ordering regressions.

Root cause: in selector.go, Select() tried to read ClientHello
via TLSConfig.GetConfigForClient but s.TLSConfig was nil because
register(cfg) -> ParseService -> handler Init ran before
SetDefaultTLSConfig was called from loader.go.
2026-06-03 20:17:20 +08:00
ginuerzh 81db46b725 refactor(handler/tunnel): code review fixes and entrypoint subpackage extraction
- Fix dead-code branch in bind.go host assignment (always use endpoint hash)
- Return descriptive error on bypass match in connect.go (was masking as success)
- Update bypass test in connect_test.go for new error behavior
- Extract entrypoint subpackage from monolithic entrypoint.go (6 files)
- Fix observeStats event-loss bug (break -> fallthrough on retry success)
- Add 47 unit tests across handler, connect, bind, metadata packages
- Add architecture doc comments to all key files
- Build and vet clean, 173 tests pass with -race
2026-06-02 23:51:55 +08:00
ginuerzh d432d28f81 refactor(handler/relay): split handler.go -> observe.go, fix observeStats event-loss bug (break->fallthrough)
Extract checkRateLimit and observeStats into their own file (observe.go).
Fix the one-tick event-loss bug in observeStats where the retry path used
'unconditional break' instead of fallthrough, causing events collected
after a successful retry to be discarded.

Add 87 unit tests across 7 files (helpers, metadata, conn, handler,
connect, forward, bind) covering all handler modes, error paths,
observer/stats integration, and conn wrapper edge cases.

handler.go: -43 lines (unused observer import, extracted functions)
observe.go: +52 lines (checkRateLimit, observeStats with fallthrough fix)
test files: +1959 lines
2026-06-02 23:51:19 +08:00
ginuerzh 31878a72ec docs(handler/tunnel): add architecture documentation and fix observeStats event loss
- Add package-level architecture doc in handler.go covering:
  - NAT traversal reverse proxy architecture
  - CmdBind/CmdConnect roles and data flow
  - Connector lifecycle and waitClose semantics
  - Entrypoint protocol dispatch (first-byte sniffing)
  - SD fallback behavior
- Add data-flow-oriented doc comments to all business files:
  - entrypoint.go: protocol dispatch, dial flow
  - connector.go: Connector/ConnectorPool semantics
  - dialer.go: two-phase dial strategy
  - tunnel.go: MaxWeight semantics, selection algorithm
  - bind.go: 6-step CmdBind flow
  - connect.go: CmdConnect flow with relay framing
  - ephttp.go, eptls.go, eprelay.go: per-protocol entrypoint flow
- Fix observeStats: after successful error retry, also flush new events
  instead of skipping the current tick (handler.go:261-271)
- Add test for observeStats retry-then-flush (handler_test.go)
2026-06-02 18:36:52 +08:00
ginuerzh e791ba47e2 refactor(handler/tunnel): split 794-line entrypoint.go into 6 files, fix 3 bugs, add 48 tests
Breaking Change: moves Connector, ConnectorPool, parseTunnelID from
tunnel.go into dedicated connector.go and id.go.

Bug Fixes:
- dialer.go: clear stale retry err so SD fallback is not masked (nil err
  from pool.Get() left previous iteration's error live)
- connect.go: check WriteTo errors in both mux and non-mux paths
- eprelay.go: use fresh relay.Response for features sent over mux
  (previously reused same resp struct after resp.WriteTo(muxConn))

Refactor:
- entrypoint.go: split ~790 lines into 6 files (ephttp, eptls, eprelay,
  epwebsocket, eplistener, entrypointsvc), moved to dedicated package
- handler.go: moved initEntrypoints/createEntrypointService to
  entrypointsvc.go
- tunnel.go: moved Connector/ConnectorPool/parseTunnelID to
  connector.go and id.go
- connect.go: moved entrypoint-originated handleConnect to eprelay.go
  (handler-side handleConnect kept in connect.go)

Tests (48 new, 88 total):
- id_test.go: parseTunnelID variants (empty, UUID, private '$', invalid)
- tunnel_test.go: Tunnel lifecycle (AddConnector, GetConnector
  weighted/closed filtering, CloseOnIdle, clean),
  Connector (NewConnector nil-opts, GetConn nil/closed session, Close,
  IsClosed), ConnectorPool (Add/Get/Close, idle cleanup, concurrency)
- dialer_test.go: SD error paths (sd.Get error, empty address)
- handler_test.go: observeStats (nil observer, cancelled context loop),
  initEntrypoints (no entrypoints configured)
- helpers_test.go: testLogger, fakeConn for handler tests
- eprelay_test.go: handleConnect ingress/dial/SD round-trip
2026-06-01 22:20:43 +08:00
ginuerzh 382d47ea12 fix: nil HTTP recorder ref in WebSocket goroutines, add tunnel loop detection
- handler/http/websocket, forwarder/sniffer_ws, sniffing/sniffer_ws: nil
  ro2.HTTP in WebSocket copy goroutines to avoid data races on the shared
  HTTP recorder object
- handler/tunnel/bind: remove ingress rule check that incorrectly
  overrode the endpoint host for non-matching ingress rules
- handler/tunnel/entrypoint: add forwarding loop detection by checking
  Gost-Forwarded-Node header for the entrypoint's own node ID
2026-06-01 18:28:01 +08:00
ginuerzh 5a09a48b2d feat: add file upload support for file handler (issue #854)
Add PUT method support to the file:// handler, allowing file uploads via
curl -T. Upload is opt-in, disabled by default — enable with ?put=true
metadata flag. Includes path traversal protection.
2026-05-31 22:48:17 +08:00
ginuerzh a9d3ffa496 fix(handler/masque): add recorder stats, idle timeout, reorder auth/DNS/200
Wire pStats into sub-handlers to capture real byte counts from QUIC
streams instead of the dummy listener conn. Resolve target address and
validate capsule-protocol after authentication instead of before 200
response to prevent dead tunnels and unauthenticated probing. Merge
pending observer events rather than replacing on consecutive failures.
Add idle read timeout to TCP tunnel relay. Add doc comments on exported
symbols and NewHandler.
2026-05-31 21:00:00 +08:00
ginuerzh 722dde5cfc fix(handler/forward): split readTimeout from pipe idleTimeout to prevent 15s download abort
The readTimeout field (default 15s) was being applied via xnet.Pipe to both
directions of a bidirectional proxy connection. During asymmetric transfers
(e.g. HTTP file download), the direction reading from the tunnel sees no
data after the initial request is forwarded, causing SetReadDeadline to fire
after 15s and abort the entire transfer.

Fix: add a separate idleTimeout field (default 0=disabled) to the metadata
structs in both forward/local and forward/remote handlers, and switch
xnet.Pipe to use idleTimeout instead of readTimeout. The readTimeout field
now only applies to the initial protocol sniffing/handshake phase.

Also document readTimeout vs idleTimeout semantics across all 24 locations
in the x/ module where these timeouts appear:
- readTimeout: handshake sniffing deadline (handlers), upstream response
  header timeout (http.Transport), or transport-level read deadline
- idleTimeout: idle read deadline per Pipe direction (0=disabled)
- ReadTimeout on Sniffer/SnifferBuilder: upstream response header/TLS
  handshake read timeout during sniffing
2026-05-31 17:05:21 +08:00
ginuerzh b8d9c79f72 fix: handle empty host in relay AddrFeature ParseFrom for bind addresses
When rtcp listener calls Router.Bind with ":8000" (port-only address),
the relay AddrFeature.ParseFrom fails because net.SplitHostPort returns
an empty host. This leaves AType at default 0, causing AddrFeature.Encode
to return ErrBadAddrType.

Fix by normalizing port-only addresses to "0.0.0.0:<port>" in both tunnel
and relay connectors before ParseFrom. Also fix error check on
resp.WriteTo in the tunnel handler's handleBind to prevent silent
protocol desync.
2026-05-31 16:00:14 +08:00
ginuerzh e543c0b0fd fix(handler/http2): apply traffic limiter + stats to forward proxy path, decouple auth I/O, add idle timeout
- Wrap non-CONNECT upstream with traffic_wrapper and stats_wrapper (was only on CONNECT path)
- Write 503 error response on forwardRequest failure instead of silent connection close
- Decouple resp.Header from w.Header() to prevent metadata header leakage/doubling in 407 responses
- Return pipeTo signal from authenticate instead of dialing inline (matches http handler pattern)
- Add idleTimeout metadata field and pass to xnet.Pipe for CONNECT tunnels
- Add 4 tests for probe resistance host forwarding and knock bypass
2026-05-30 20:06:56 +08:00
ginuerzh 6ccaae0573 refactor(handler/http2): split handler into 3 focused files with 52 tests
Extract authenticate/probe-resistance to auth.go and roundTrip/forwarding
to proxy.go, following the handler/http/ pattern. Export sentinel errors
(ErrAuthFailed, ErrWrongConnType) for precise test assertions. Fix
flushWriter panic recovery to handle non-string/non-error panics. Default
HTTPS port to 443 when no port is specified in the Host header.
2026-05-30 18:01:19 +08:00
ginuerzh a33c6f4a92 test(handler/http): add 25+ tests for probe resistance, MITM, bypass, and edge cases
+698/-3 across auth_test, connect_test, handler_test, metadata_test,
proxy_test, and websocket_test. Covers probeResistanceResponse (web/file/
host/code types), handleRequest (bypass/UDP-disabled/CONNECT edge cases),
setupTrafficLimiter with observer, observeStats lifecycle, MITM metadata,
HTTP/1.0 keep-alive proxyRoundTrip, websocket body recording, and sniff
timeout handling. Fixes SetDeadline signatures from any→time.Time.
2026-05-30 17:54:27 +08:00
ginuerzh f8ddb193cb refactor(handler/forward/remote): split handler into 6 focused files with 41 tests
Split the 339-line handler monolith and 1169-line test blob into 11 files
(5 source + 6 test) following the handler/forward/local/ pattern.

Source files: handler.go (core), forward.go (raw forwarding),
sniffing.go (SnifferBuilder + protocol dispatch), util.go (errors +
recorder + rate limit), metadata.go (config parsing).

Fixes: add sync.Mutex for hop access (race), use sentinel errors for
errors.Is compatibility, add nil-addr guard in checkRateLimit, reuse
SnifferBuilder via Build() instead of per-call construction.
2026-05-30 16:27:20 +08:00
ginuerzh 32c3d33afd refactor(handler/forward/local): split handler into 6 focused files with 40 tests at 100% coverage
Extract Handle into handleRawForwarding, handleSniffedProtocol, SnifferBuilder,
newRecorderObject, and checkRateLimit across forward.go, sniffing.go, and
util.go. Replace redundant x509.ParseCertificate with tlsCert.Leaf (already
populated by tls.LoadX509KeyPair since Go 1.23).
2026-05-30 16:09:48 +08:00
ginuerzh 23b58ddd23 refactor(handler/http): extract Authenticator, SnifferBuilder, and normalizeRequest as testable units
Extract three pure-logic components from httpHandler to eliminate I/O
coupling from auth and sniffing construction, enabling synchronous unit
tests and reducing per-request allocation in sniffAndHandle:

- Authenticator struct with AuthResult return type — auth decisions no
  longer write to the connection; callers handle response I/O. Auth
  tests drop net.Pipe/goroutines for direct return-value assertions.
- SnifferBuilder pre-built in Init and reused per-connection via Build(),
  replacing inline sniffing.Sniffer{} construction in sniffAndHandle.
- normalizeRequest extracted to util.go with NormalizedRequest type,
  collapsing 20 lines of inline URL/normalisation into a single call.
- knockMatch extracted as standalone pure function.
- clampBodySize exported as ClampBodySize for cross-package use.
- util_test.go with 22 tests covering utility functions.
- helpers_test.go consolidates shared test fakes (logger, observer, conn).
2026-05-29 00:14:44 +08:00
ginuerzh c246a1d4fa feat(handler/http,http2): support comma-separated hostnames in probeResistance knock
Knock previously accepted a single hostname. Now it accepts multiple
comma-separated hostnames; probe resistance is bypassed if the request
hostname matches any entry in the list. Matching is case-insensitive
and whitespace around entries is trimmed.
2026-05-28 23:20:27 +08:00
ginuerzh 3246b39c93 refactor(handler/http): split handler monolith into 7 focused files with 96 unit tests
Extract the 1024-line handler.go into concern-focused files:
  util.go       — 5 pure functions (decodeServerName, basicProxyAuth, upgradeType,
                  normalizeHostPort, buildConnectResponse) — 100% coverage
  auth.go       — authenticate (5 probe-resistance strategies + knock) + checkRateLimit
  connect.go    — handleConnect, sniffAndHandle, dial, setupTrafficLimiter
  proxy.go      — handleProxy keep-alive loop, proxyRoundTrip, handleUpgradeResponse
  websocket.go  — WebSocket frame sniffing/recording with rate-limited sampling
  udp.go        — UDP-over-HTTP relay with SOCKS5 tunnel
  metadata.go   — metadata struct, parseMetadata, probeResistance type

Key improvements:
- Transport injection (http.RoundTripper field) enables testing without real network
- Nil Router guards in dial, handleUDP, and nil Addr guard in checkRateLimit
- Pure functions converted from methods to package-level (no state dependency)
- setupTrafficLimiter returns cleanup closure to preserve defer lifetime
- handleConnect accepts caller's resp for correct recorder status capture
- Comprehensive package doc with full request-flow documentation

96 tests: 100% on pure functions, 86% on metadata parsing, 55% overall (integration
paths verified by e2e tests).
2026-05-28 23:06:37 +08:00
ginuerzh f4be111420 fix(handler/http): host validation with port split, sniffer ownership guard, body leak, probe resistance hardening
- Split host:port in Host header before DNS/IP validation, accept bare IPs
- Guard sniffer connection ownership with snifferHandled flag to prevent
  double-close when sniffers take over the tunnel
- Close req.Body in handleProxy keep-alive loop on both error and success
  paths to prevent goroutine leaks from idle HTTP transport connections
- Log all resp.Write errors (5 call sites) instead of silently discarding
- Respect resp.Close for all responses, not just ContentLength >= 0,
  fixing unnecessarily closed chunked keep-alive connections
- Harden probe resistance: validate strconv.Atoi result, add 15s timeout
  to web redirect HTTP client, document pr.Knock empty/set/mismatch logic
2026-05-28 21:32:06 +08:00
ginuerzh 776f045896 refactor(handler/forward): extract 6 helpers from remote Handle, add 44 unit tests
Extract newRecorderObject, selectTarget, sniffingDial, buildSniffer,
handleSniffedProtocol, and handleRawForwarding from Handle (200→87 lines).
Move nil Router guard before sniffing for early failure. Log previously
silent sniff and pipe errors at Debug level. Apply readTimeout to Pipe.
Append :0 when target addr lacks a port. Reorder metadata fields and
add doc comments on all exported symbols.
2026-05-28 20:40:13 +08:00
ginuerzh 9eeb88e6a2 refactor(handler/forward): extract 5 helpers from Handle, add 39 unit tests 2026-05-28 20:19:19 +08:00
ginuerzh 19aa429bea fix(handler/forward): add nil Router guard, log discarded sniff/pipe errors, defer sniffer alloc
- Return clear error when Router is nil instead of panicking
- Capture and log sniffing.Sniff and xnet.Pipe errors at Debug level
- Move dial closure and Sniffer construction into HTTP/TLS switch branch
  to avoid unnecessary allocation on non-HTTP/TLS traffic
- Merge ProtoHTTP and ProtoTLS cases, branch internally on proto
- Add doc comments on NewHandler and Handle
- Add comment explaining nil hop is valid (no forwarder config)
- Pass readTimeout to xnet.Pipe via WithReadTimeout
2026-05-27 23:05:32 +08:00
ginuerzh 7e3183488b fix(handler/file): fix deadlock, conn leak, and nil Addr; add 39 tests
Fix bugs in the file handler: unbuffered send channel deadlock on Close,
conn leak when send drops on done, and Addr() returning nil. Add done-
priority select in send(), explicit ln.Close() in Close(), Unwrap() on
responseWriter for http.ResponseController, and nil guards.

Also add package doc, NewHandler doc, and 39 unit tests covering the
listener, responseWriter, handler lifecycle, auth, and file serving.
2026-05-27 22:49:59 +08:00
ginuerzh 79718ee19e fix(handler/dns): buffer pool leak, write deadline, async error logging, EDNS0 buffer
Fix bufpool leak when PackBuffer fails by extracting packResponse helper.
Add write deadline before conn.Write to prevent goroutine hangs on slow
clients. Log async exchange errors instead of silently discarding them.
Raise defaultBufferSize from 1024 to 4096 to match EDNS0 standard.
Deduplicate lookupHosts TypeA/TypeAAAA branches.
2026-05-26 21:22:19 +08:00
ginuerzh dd76e9f685 fix(handler/dns): apply readTimeout, fix async context leak, add 40 tests
- Apply parsed readTimeout as connection read deadline (was dead code)
- Use context.WithoutCancel for async cache refresh goroutine
- Add doc comments to all exported symbols
- Add 40 tests covering metadata parsing, init, rate limiting,
  exchanger selection, host lookup, cache, bypass, async refresh,
  and concurrent request handling
2026-05-26 20:55:55 +08:00
ginuerzh b3424b769e fix(handler/api): add nil guard, propagate Shutdown error, doc comments, 20 tests
- Return errHandlerNotInitialized when Handle called before Init
- Propagate s.Shutdown(ctx) error instead of silently discarding
- Add doc comments to all exported symbols
- Add 20 tests covering constructor, init, metadata parsing, HTTP
  endpoints via httptest, Handle lifecycle, singleConnListener, and
  compile-time interface assertions
2026-05-26 20:44:23 +08:00
ginuerzh b991baaf72 fix(io,tunnel): nil deref in RecorderObjectFromContext, CloseRead checked Writer, SetReadDeadline no unwrap
- 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
2026-05-24 17:51:16 +08:00
ginuerzh 3f73c82d00 fix(ss): address review findings for PR #96 — nil guards, resource leaks, dead code
- 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
2026-05-22 21:40:33 +08:00
ginuerzh 5433ca580c Merge remote-tracking branch 'origin/pr/96' 2026-05-22 21:07:43 +08:00
ginuerzh 174bc082d1 fix(tunnel): data race in CloseOnIdle and goroutine leak in sniffingWebsocketFrame
- Use write lock (Lock) instead of read lock (RLock) in CloseOnIdle since
  it modifies the close channel, preventing a race with Close() that could
  panic on double-close of channel.
- Buffer sniffingWebsocketFrame errc to capacity 2 and close both
  connections on first error to ensure the remaining copy goroutine
  unblocks and exits cleanly.
2026-05-22 16:31:37 +08:00
kLiHz 3c8995027a adapt newest go-shadowsocks2 lib 2026-05-22 13:35:01 +08:00
ginuerzh 01a2bbaa11 fix(masque): address review findings for PR #76
- 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).
2026-05-21 22:50:29 +08:00
ginuerzh 66b53580af merge: PR #76 — MASQUE CONNECT-UDP and CONNECT-TCP support (RFC 9298/9114)
Extend MASQUE implementation to support TCP tunneling via standard
HTTP/3 CONNECT method, in addition to UDP via CONNECT-UDP.
2026-05-21 22:50:23 +08:00
Andrew Beresford 290e9c37d5 Make pipe read timeout configurable via idleTimeout metadata
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
2026-05-08 11:31:53 +01:00
Jason Lyu cd7bf9521f fix sshd connection type 2026-04-21 20:49:28 +08:00
David Manouchehri 7625973ca1 Add MASQUE/CONNECT-UDP support (RFC 9298)
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)
2026-04-21 19:53:07 +08:00