Commit Graph

627 Commits

Author SHA1 Message Date
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 a2cef9639d test(sniffing): add 20 unit tests, coverage from 34.2% to 58.9%
Add tests for Sniff/isHTTP protocol detection, setHeader, h2Handler.ServeHTTP
(mock RoundTripper), HandleHTTP bypass/body-recording, HandleTLS error path,
handleUpgradeResponse websocket path, and copyWebsocketFrame read error.
2026-05-27 21:30:52 +08:00
ginuerzh 4f526c2aee refactor(sniffing): split sniffer monolith into focused files, extract testable helpers
Split ~850-line sniffer.go into 6 focused files (http, h2, tls, ws,
rewrite, test), extract pure helpers (clampBodySize, normalizeHost,
effectiveReadTimeout), fix "DeafultSampleRate" typo, add doc comments
on all exported symbols, and add 22 unit tests.
2026-05-27 21:21:40 +08:00
ginuerzh 87b055a83b fix(icmp): ICMP tunnel not working on Windows due to wildcard bind (#98)
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.

Fixes go-gost/x#36
2026-05-27 21:02:26 +08:00
ginuerzh 618cc7fd9c fix(plugin): CloseIdleConnections silent no-op when tokenTransport wraps HTTP transport
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.
2026-05-27 20:37:14 +08:00
ginuerzh 3646c23398 refactor(forwarder): extract resolveHTTPNode and resolveTLSNode helpers, add tests
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.
2026-05-26 23:15:15 +08:00
ginuerzh aba7e2a256 refactor(forwarder): split sniffer monolith into focused files, extract testable helpers
Split ~1250-line sniffer.go into sniffer_http.go (HTTP handling, dial, round-trip),
sniffer_tls.go (TLS MITM, termination), sniffer_h2.go (HTTP/2), sniffer_ws.go
(WebSocket frame copy/record), and sniffer_rewrite.go (upgrade, body rewrite).

Extract clampBodySize, normalizeHost, effectiveReadTimeout as package-level
functions to simplify testing. Add 22 tests covering pure functions, option
setters, HTTP proxy integration, WebSocket frame copy, and edge cases.
2026-05-26 22:48:27 +08:00
ginuerzh 92564a0c8c fix(forwarder): ReadTimeout race, goroutine leak, PeerCertificates panic, stale error return
- 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
2026-05-26 21:58:30 +08:00
ginuerzh fb0ee8ead4 refactor(matcher): replace cidranger with zero-alloc trie, migrate to netip
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.
2026-05-26 21:38:55 +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 1510f841c3 refactor(bypass): named decision types, consolidated pattern set, remove dead code
Replace boolean bypass logic with bypassDecision enum (decisionBypass/decisionProxy),
consolidate four matcher fields into a single patternSet struct for atomic swaps,
extract classifyPatterns as a pure function, and remove unused matched() method
and slices import. Add 204 lines of tests covering decisions, pattern sets,
and group evaluation logic.
2026-05-26 20:27:21 +08:00
ginuerzh 1c07cf6394 fix(service): default nil logger, fix Events() allocation, collect Close errors
- Default nil logger to Nop() in NewService to prevent panics
- Fix Events() returning 20-element slice padded with zero values
- Collect and join all errors in Close() instead of discarding
- Remove unnecessary variable shadow in execCmds
- Add doc comments to all 22 exported symbols
- Add 34 tests covering status, serve loop, close, and edge cases
2026-05-25 23:47:47 +08:00
ginuerzh aabebd047b fix(selector): safe type assertion, clean up debug logging, add doc comments and 64 tests
Replace bare type assertion in ParallelStrategy with comma-ok check to
prevent panic on non-Node inputs. Downgrade noisy Infof hash-selection
log to Tracef and remove Chinese-language debug output. Add doc comments
to all exported symbols in weighted.go.
2026-05-25 23:38:35 +08:00
ginuerzh 18f39f940b fix(sd): add nil service guards, improve error messages, remove unused logger
- Add nil service guards to Register/Deregister/Renew in gRPC and HTTP
  plugins to prevent nil pointer dereferences
- Remove unused log field from grpcPlugin and httpPlugin
- Prefix HTTP error messages with operation context (sd register/deregister/renew/get)
- Return gRPC Register error directly instead of logging + returning
- Add 33 unit tests covering all operations, nil guards, and error paths
2026-05-25 23:04:27 +08:00
ginuerzh b7a4cb0251 fix(routing): fix wildcard host suffix matching and PathRegexp error message
- Fix Host(".example.com") incorrectly matching bare "example.com" by
  using HasSuffix(reqHost, host) instead of HasSuffix(reqHost, host[1:])
- Fix PathRegexp matcher error message saying "PathPrefix" instead of
  "PathRegexp"
- Add doc comments to NewMatcher and Tree types
- Add 28 unit tests covering all matcher types, boolean operators,
  edge cases, and parameter validation
2026-05-25 23:03:53 +08:00
ginuerzh 4443b0b964 fix(router): close httpLoader on shutdown, log parse errors, default nil logger
- Add missing httpLoader.Close() in localRouter.Close() to prevent
  resource leak
- Log parse errors from file/redis/http loaders instead of silently
  discarding them
- Add nil reader guards before calling parseRoutes in load()
- Default nil logger to xlogger.Nop() to prevent nil panics
- Use context.Background() instead of context.TODO() for root context
- Use strings.ReplaceAll instead of deprecated strings.Replace with -1
- Add doc comments to all exported symbols
- Add 27 unit tests + 1 benchmark
2026-05-25 23:03:19 +08:00
ginuerzh f20e151cfa refactor(resolver): extract preference constants and shouldReturn helper
Replace 10 raw "ipv4"/"ipv6" string literals with preferIPv4/preferIPv6
constants, extract the duplicated fallback-condition check (repeated 4x
across resolve and lookupCache) into shouldReturn, and fix a misleading
doc comment on resolvePreference's default return.
2026-05-25 21:54:54 +08:00
ginuerzh 039bcc9af9 fix(resolver): fix IPv4/IPv6 fallback asymmetry, data race, and caller mutation bugs
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.
2026-05-25 21:44:58 +08:00
ginuerzh 28d3ffa310 fix(resolver): fix async context leak, gRPC error swallowing, add 48 tests
Fix async resolve goroutine using caller's cancelable context by
switching to context.WithoutCancel. Fix NewGRPCPlugin silently
returning broken resolver on connection failure. Fix "resolover"
typo in log field. Add doc comments to all exported symbols.
2026-05-25 20:52:19 +08:00
ginuerzh acce86c0e4 fix(registry): log Unregister Close errors, add doc comments and 59 unit tests
Log close errors in Unregister instead of silently discarding them.
Add doc comments to all exported symbols across 20 registry files.
Add comprehensive tests covering base registry, all wrapper types,
hot-reload delegation, nil-fallback semantics, and global accessors.
2026-05-25 20:23:06 +08:00
ginuerzh b1b7500c2f test(recorder): add 55 unit tests for file, HTTP, TCP recorders and HandlerRecorderObject
Covers Record, Close idempotency, nil guards, write errors, concurrent writes,
context propagation, short-write loop, JSON round-trip, and all option functions.
2026-05-25 00:15:35 +08:00
ginuerzh 64a16fafbc fix(recorder): propagate context, handle short writes, add nil guards, idempotent Close, and doc comments
- httpRecorder: use http.NewRequestWithContext instead of http.NewRequest
- tcpRecorder: loop Write to avoid short-write data loss
- fileRecorder: guard against nil out in Record and Close
- plugin/grpc, plugin/http: handle json.Marshal errors instead of ignoring
- fileRecorder, redis*Recorder: idempotent Close via sync.Once
- All exported symbols: add doc comments
2026-05-24 23:58:28 +08:00
ginuerzh 689ba36e92 fix(observer): remove dead nil checks from udpConn, add unit tests
The WrapUDPConn constructor returns nil when either arg is nil, so
c.stats is always non-nil in all udpConn methods. Remove 8 redundant
nil guards that were inconsistent with packetConn (which already
skipped them).

Add 65 unit tests across plugin, stats, and wrapper packages covering
nil safety, race conditions, double-close, event marshaling, and
reset-traffic semantics. Replace magic numbers in tests with named
Kind constants.
2026-05-24 23:47:48 +08:00
ginuerzh 7c95d40e05 fix(observer): add nil guards, fix resource leak, silent event drops, and missing doc comments
- WrapUDPConn, WrapPacketConn, WrapListener: add nil guards for pc/ln params
- NewGRPCPlugin: return no-op observer instead of nil on connection error
- gRPC plugin: fix resource leak by wiring Close() through observerWrapper
  and service.Close() lifecycle
- Both plugins: log unknown event types instead of silently dropping them
- httpPlugin: remove dead nil check for always-non-nil client field
- Stats.Reset: update core interface doc to match implementation behavior
- Add doc comments to all exported symbols across the observer package
2026-05-24 23:13:52 +08:00
ginuerzh bc3d12ec2c fix(metrics): add doc comments, fix labels mutation and nil returns, add idempotent Close, add nil guards, add tests
- Fix promMetrics.Gauge/Counter/Observer mutating caller's labels map by
  using maps.Copy instead of direct assignment
- Fix Gauge/Counter/Observer returning nil for unknown metric names
  (now return noop implementations)
- Fix metricService.Close() race with sync.Once for safe concurrent calls
- Fix SetDSCP returning nil instead of errUnsupport on unsupported ops
- Add nil guards to WrapConn, WrapPacketConn, WrapUDPConn, WrapListener
- Add doc comments to all exported symbols
- Add 45 unit tests (metrics, noop, prom, service, wrapper)
2026-05-24 22:50:41 +08:00
ginuerzh 64f9a048f8 feat(limiter/traffic): add burst support, dropped-packet counters, and cache fixes
- Add NewLimiterWithBurst(rate, burst) for independent burst control
- Extend parseLimit to accept optional 4th field as burst size
- Add DroppedPacketCounter interface with DroppedPackets() for packet/udp conns
- Export ErrRateLimited sentinel for rate-limit error checks
- Fix IP-level cache expiration (NoExpiration → defaultExpiration) to prevent
  unbounded growth; reset TTL on access in In/Out
- Short-circuit single-limiter path to avoid limiterGroup allocation
- Add nil guard in cachedTrafficLimiter when both old and new values are nil
- Remove unused ctx field from wrapper structs
2026-05-24 21:52:02 +08:00
ginuerzh a9d94e7009 fix(metadata): nil-Metadata from NewMetadata(nil), missing float32 in GetFloat; add doc comments and tests
NewMetadata(nil) previously returned a nil Metadata interface, causing
panics on direct .Get()/.IsExists() calls. Now returns an empty map.
GetFloat added float32→float64 promotion, matching GetString behavior.
Doc comments for all 13 exported symbols across both packages.
41 unit tests (11 metadata + 30 util) at 100% coverage.
2026-05-24 20:59:30 +08:00
ginuerzh dc99f4731f docs(limiter/traffic): add doc comments, unit tests 2026-05-24 20:54:34 +08:00
ginuerzh e9372ea44a fix(limiter/traffic): infinite Write loop on zero burst, missing httpLoader.Close, stale reload values, ignored WaitN error, silent UDP drops, SplitHostPort fallback 2026-05-24 20:20:01 +08:00
ginuerzh 9bbd7da526 fix(limiter/rate): short-circuit Allow on denial, add missing httpLoader.Close, doc comments, tests
- limiterGroup.Allow(): return false immediately on first denial instead of
  continuing through all limiters (wasting tokens on subsequent limiters).
  Sort limiters by Limit() so most restrictive fires first.
- rateLimiter.Close(): add missing httpLoader.Close() to prevent resource leak.
- Add doc comments for all exported symbols (package, constants, Options,
  NewRateLimiter, NewLimiter, ErrRateLimit, generators).
- Add rate_test.go with 59 unit tests covering generators, limiter groups,
  parsing (limit/line/patterns), reload, loader merge, Close behavior,
  and priority ordering (exact IP > CIDR > $$ > $).
2026-05-24 20:09:26 +08:00
ginuerzh 05fe690f67 test(limiter/conn): add unit tests for conn limiter and wrappers 2026-05-24 19:38:54 +08:00
ginuerzh fa708f4b5f docs(limiter/conn): add doc comments, fix nil guards and missing Close
Add package and exported symbol doc comments across conn, generator,
limiter, and wrapper packages. Fix nil receiver guard in
connLimitSingleGenerator.Limiter, add missing httpLoader.Close call,
return context.Background instead of nil in serverConn.Context, return
explicit error on connection limit exceeded, and simplify Allow logic.
2026-05-24 19:38:07 +08:00
ginuerzh 0e96f602fa fix(matcher,plugin): case-insensitive matching, port accumulation, nil guards, doc comments
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.
2026-05-24 18:18:42 +08:00
ginuerzh 51455da96f fix(loader): wire context into HTTP request, guard nil opts in Redis list/hash
- HTTPLoader.Load: http.NewRequest → NewRequestWithContext so caller
  cancellation/deadlines propagate to the outgoing request
- RedisListLoader, RedisHashLoader: add nil-guard before calling opt()
  (already present in StringLoader, SetLoader, and HTTPLoader)
- Add doc comments for all 10 exported symbols (package, interfaces,
  constructors, option types, option funcs, DefaultRedisKey)
- Add loader_test.go with 32 tests covering FileLoader, HTTPLoader
  (context cancel, error status, empty/large body), Redis options,
  nil-guard safety, and interface satisfaction checks
2026-05-24 18:04:02 +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 501051ce4d fix(ingress): nil deref in parseRules, missing httpLoader.Close, swallowed SetRule error
- parseRules: add nil guard before accessing rule.Hostname (parseLine
  returns nil for comments, blanks, and invalid lines)
- Close: call httpLoader.Close() alongside fileLoader and redisLoader
- grpcPlugin.SetRule: log error and return false instead of discarding it
- Add 28 unit tests covering parseLine, parseRules, GetRule wildcard
  matching, reload, Close, and all loader types
2026-05-24 17:27:17 +08:00
ginuerzh 011759d888 docs(hosts,hop): add doc comments, fix missing httpLoader.Close, accumulate reload errors
- hosts/hosts.go: add package and symbol doc comments, fix missing
  httpLoader.Close() in Close()
- hosts/plugin: add doc comments for HTTP and gRPC plugin types
- hop/hop.go: add doc comments, accumulate reload/parse errors via errors.Join
  instead of silently discarding them
- hop/plugin/http.go: add doc comments and missing Close() method
- Add unit tests for hosts (580 lines) and hop (991 lines)
2026-05-24 16:00:53 +08:00
ginuerzh 419f4c4c73 docs(ctx): add doc comments, remove dead WithContext interface, simplify HashFromContext
Remove unused WithContext interface (zero references in codebase), add
doc comments for all 14 exported symbols, and simplify HashFromContext
to match the one-liner pattern used by the other four getters.
Add 22 unit tests covering round-trip, empty context, wrong type, nil
values, multiple values, independent keys, and the Context interface.
2026-05-24 14:26:45 +08:00
ginuerzh 4efb4b9974 fix(direct): guard nil dialer and nil logger in Connect, add doc comments
Add nil checks for connect-options dialer and logger to prevent
nil-pointer panics when Connect is called without a DialerConnectOption
or LoggerOption. Add package and NewConnector godoc comments.

Add 10 unit tests covering construction, Init metadata parsing,
Connect success/reject/dial-error paths, nil dialer, nil logger,
and the reject conn stub.
2026-05-24 14:19:08 +08:00
ginuerzh effba3b690 docs(parsing): add package and symbol doc comments
Add godoc comments for all 62 exported symbols across 20 files in
config/parsing/: 23 MDKey constants, 35 Parse*/List/Default* functions,
3 TLS helpers, 1 Args struct with 7 fields, and the package doc.
2026-05-24 13:58:37 +08:00
ginuerzh 2b1e4ca3a7 test(parsing): add 229 unit tests across 18 config/parsing packages
Covering nil-input safety, plugin backends (HTTP/gRPC/default), loaders
(File/HTTP/Redis), selector strategies, edge cases (empty/invalid inputs),
and hop-to-node metadata inheritance. All tests passing.
2026-05-24 13:34:33 +08:00
ginuerzh 9febb23bc9 fix(config): stop mutating shared config structs during parsing
Prevent data loss and nil panics across 5 parse functions:
- chain: nil-guard hop entries to avoid deref on empty YAML lists
- hop: build merged metadata map instead of writing inherited values
  into the original NodeConfig; swap+restore around ParseNode call
- node: use local connCfg/dialCfg instead of overwriting cfg.Connector
  and cfg.Dialer fields; only fill in Type when empty
- parser: preserve existing config file fields when env vars override
  Level/Addr (was replacing the entire struct)
- router: only update ipNet from dst CIDR if parse succeeds, keeping
  the route.Net fallback instead of overwriting with nil
2026-05-24 12:56:54 +08:00
ginuerzh 8390ccadab test(config): add unit tests for loader, doc comments, fix fmt.Errorf misuse
- Add 808-line loader_test.go covering registerGroup, register, and Load
- Add package and exported symbol doc comments to loader.go
- Fix fmt.Errorf(resp.Status) → errors.New(resp.Status) in sd/plugin/http.go
  (resp.Status is a plain string, not a format string)
2026-05-24 12:36:51 +08:00
ginuerzh 82e7e50120 fix(config): nil deref on Load, SoMark/Metadata gating, netns copy-paste bug, and partial-reg-failure side effects
- loader: guard cfg == nil in Load() to prevent nil-pointer dereference on
  cfg.Log / cfg.TLS access.
- loader: defer logger.SetDefault and parsing.SetDefaultTLSConfig until
  after register() succeeds, so a failed reload does not leave global
  state (logger, default TLS) pointing at the new config while components
  remain from the old config.
- loader: extract registerGroup[T] helper to eliminate repeated
  unregister-then-register boilerplate.  Entries are parsed and collected
  before unregistering; a parse error now preserves the previous group
  (old code unregistered first, then parsed, leaving an empty registry on
  parse failure).
- hop: move cfg.SockOpts.Mark extraction outside the cfg.Metadata != nil
  block so the socket mark is read even when hop-level metadata is absent.
- hop: fix copy-paste error in netns inheritance: v.Name was incorrectly
  stored as MDKeyNetns instead of v.Netns (introduced in f71351f).
2026-05-24 10:15:37 +08:00
ginuerzh 5a838a7d47 fix(dtls): upgrade pion/dtls v2.2.6 to v3.1.1 fixing CVE-2026-26014
Upgrade github.com/pion/dtls from v2.2.6 to v3.1.1 to fix nonce reuse
vulnerability in AES-GCM ciphers (GHSA-9f3f-wv7r-qc8r). Migrate from
deprecated Config-struct API to ListenWithOptions/ClientWithOptions
options-based API.

v2 Config fields mapped to v3 functional options:
- Certificates, InsecureSkipVerify, ExtendedMasterSecret, ServerName,
  RootCAs, ClientCAs, ClientAuth, FlightInterval, MTU

ConnectContextMaker removed — no longer exists in v3; explicit
HandshakeContext(ctx) on *Conn is the replacement for timeout control.
2026-05-23 18:48:21 +08:00
ginuerzh 982ffa8149 test(cmd): add unit tests achieving 93.8% coverage 2026-05-23 18:36:24 +08:00
ginuerzh 1f62219c1a docs(cmd): add package and symbol doc comments 2026-05-23 18:14:05 +08:00
ginuerzh ee57a383c5 fix(cmd): shallow-copy leaks in node/service expansion, inconsistent auth priority
Three bugs in CLI-to-config conversion:

1. Comma-separated -F nodes shared Connector/Dialer/Metadata pointers
   due to struct value copy; add deep-copy helpers per node.

2. Port-range-expanded -L services shared Handler/Listener/Metadata
   pointers; deep-copy per service so metadata mutations don't cross-talk.

3. buildServiceConfig's ?auth= query param unconditionally overwrote
   URL-embedded auth; buildNodeConfig used fallback-only. Align both
   on URL-auth-first semantics (query param as fallback).
2026-05-23 17:44:39 +08:00