feat: add mux.cool outbound#2980
Conversation
|
@KT-Yeh could you look pls? |
|
@wwqgtxx это тоже будет закрыто или хотя бы прочитано описание и код? |
|
It won't be closed for now, but it won't be merged in the short term either. The changes in this PR are extensive and clearly largely AI-generated, requiring significant effort to review. Furthermore, while the feature is interesting, its suitability for merging is open to debate: The implementation here is heavily biased towards From another perspective, neither core has seen meaningful modifications to |
С учетом того, что в xray никто не трогает mux.cool не думаю, что потребуется вообще, что либо менять, а если возникнут ошибки, я сам посмотрю и подготовлю испралвения. Я понимаю, что есть красивый smux, но к сожалению xray несколько недальновидны и не занимаются повышением качества в данном аспекте |
Summary
This PR adds native Xray-compatible
mux.coolclient and server support for TCP, UDP, and XUDP traffic.New,Keep,End, andKeepAliveframes.v1.mux.cool:9527.v1.mux.cool:9527carriers with the native VLESS Mux command, matching Xray-core in both client/server directions.v1.mux.coolcarriers through the shared sing-based listener path, including Trojan, VMess, and VLESS listeners.reject,allow, andskippolicies.smuxandmux.cool.skip.Configuration
Parameters
enabledEnables
mux.coolfor the proxy.When enabled, logical TCP, UDP, and XUDP sessions can be transported over multiplexed TCP carriers connected through the underlying proxy to
v1.mux.cool:9527.Default:
false.max-concurrencyMaximum number of simultaneously active logical sessions on one primary Mux carrier.
When every existing carrier reaches this limit, another physical carrier is opened. If
xudp-concurrencyis zero, this limit applies to TCP, UDP, and XUDP sessions in the shared pool.Default:
8.A zero or omitted value uses the default.
max-connectionsMaximum total number of logical sessions that one carrier may accept during its lifetime.
After a carrier has accepted this many logical sessions, it stops accepting new sessions. Existing sessions continue until completion, while new sessions are assigned to another carrier.
Despite the option name, this is not a limit on the number of physical carrier connections. It is a lifetime logical-session limit for each carrier.
The limit applies independently to carriers in the primary and dedicated packet pools.
Default:
128.A zero or omitted value uses the default.
max-carriersStrict maximum number of physical TCP carrier connections owned by this
mux.coolwrapper.The limit is shared by the primary pool and the optional dedicated UDP/XUDP packet pool. In-flight carrier dials count toward the limit, preventing concurrent dial attempts from overshooting it.
When the limit is reached, new logical sessions wait for capacity on an existing carrier or for a physical carrier slot to be released. Waiting respects caller context cancellation and pool shutdown. Mux is not bypassed and the limit is never silently exceeded.
Carrier capacity is released after dial failure, carrier rotation, idle cleanup, carrier failure, or pool shutdown.
Default:
0(unlimited, preserving the previous behavior).A negative value is rejected during configuration parsing.
xudp-concurrencyControls packet-pool isolation and the maximum number of active UDP/XUDP sessions per packet carrier.
0: TCP, UDP, and XUDP use the same primary carrier pool.0: creates a dedicated UDP/XUDP packet pool and uses the configured value as its per-carrier active-session limit.0: rejected as invalid configuration.A dedicated packet pool prevents long-lived UDP/XUDP sessions from consuming per-carrier TCP session capacity. The implementation routes all packet sessions through this pool when it is enabled, including sessions without an XUDP Global ID. When
max-carriersis non-zero, both pools still share the same physical connection budget.Default:
0.xudp-proxy-udp443Controls how UDP traffic targeting port
443, typically QUIC or HTTP/3, is handled.Supported values:
reject: reject UDP/443 before opening a carrier. This is the default and matches Xray-core behavior.allow: transport UDP/443 through the mux packet path.skip: bypassmux.cooland delegate UDP/443 directly to the underlying proxy.The policy applies only to UDP/443. Other UDP destinations continue through the shared or dedicated packet pool.
Default:
reject.Unknown values are rejected during configuration parsing.
Example Behavior
With the configuration shown above:
Protocol Support
The implementation supports:
Keepframes.TCP, UDP, and XUDP failures are propagated to the caller without silently bypassing Mux.
The only bypass behavior is the explicit
xudp-proxy-udp443: skippolicy.Connection Management
Each carrier tracks:
The pool supports:
max-carriersis configured.When a dedicated packet pool is configured, it has independent workers, concurrency accounting, carrier rotation, and idle cleanup. Its physical carriers still consume the same
max-carriersbudget as the primary pool.Error Handling
PacketConn, deadlines, carrier failure, or pool shutdown.Endat most once.skipmode returns the underlying proxy result directly.Performance
The hot paths were optimized through a bounded 20-pass benchmark- and profile-driven performance cycle.
Each pass started from a benchmark, CPU profile, allocation profile, contention profile, or process-level observation. Only changes with measurable improvements and preserved protocol semantics were retained.
Implemented optimizations:
DecodeFrameownership model unchanged.Keep + Dataframes.sync.Pool.WaitReadFromsupport for packet sessions.netip.Addrvalues instead of repeated IP string conversions.selectoverhead in steady-state UDP/XUDP writes while preserving deadline reset and close-cause behavior.Representative Results
Measured on an Apple M3 Max. Results are environment-dependent.
The internal pooled decoder is used by carrier workers. The public
DecodeFramefunction continues to return independently owned payload memory so external callers are not exposed to pooled-buffer lifetime requirements.Testing
Protocol and Codec Coverage
0ee156e75c9546a713f6c88c0bd14f5ff953c567.New,Keep,End, andKeepAliveframe tests.Session Behavior
Endtests.WaitReadFrombehavior tests.Server Behavior
mux.coolcarriers are drained.Pool Behavior
Configuration and UDP/443 Behavior
smuxandmux.coolconflict tests.max-carriersconfiguration tests.allowtests.skiptests.skipdelegates directly to the base proxy.Performance Regression Coverage
Persistent benchmarks cover:
ReadFrom.WaitReadFrompaths.Process-Level End-to-End Tests
The integration suite includes a physical-carrier limit test that:
mux.coolwithmax-concurrency: 8andmax-carriers: 2.Run it with:
It also includes a bidirectional cross-runtime compatibility matrix that builds and starts real mihomo and Xray-core processes and verifies:
v1.mux.coolcarriers.Normal UDP and XUDP are exercised as distinct wire modes. The normal-UDP scenarios use a zero Global ID, while the XUDP scenarios use source identity and an 8-byte Global ID. Independent TCP, UDP, and DNS echo services verify traffic outside either proxy process.
The test uses
XRAY_E2E_BINARYwhen provided. Otherwise, it builds Xray-core fromXRAY_CORE_ROOTor from a siblingXray-corecheckout.Run the compatibility matrix with:
Validation Results
go test ./...suite passes.adapter/outboundandtransport/muxcoolpackages pass undergo test -race.go test -race -tags=integration.go vet ./adapter/outbound ./transport/muxcoolpasses.git diff --checkpasses.transport/muxcoolstatement coverage:82.9%.Compatibility
The wire format and XUDP behavior are based on Xray-core revision:
The feature is configured under the
mux.coolproxy key. Mihomo uses kebab-case option names:The XUDP options correspond to Xray-core’s
xudpConcurrencyandxudpProxyUDP443fields.max-carriersis a mihomo extension that places a strict total cap on physical TCP carriers.For VLESS, mihomo encodes a carrier targeting
v1.mux.cool:9527with the native VLESS Mux command instead of an ordinary TCP destination request. This matches Xray-core's VLESS behavior and is covered by both unit tests and real-process tests in both client/server directions.mux.coolis applied as a generic outbound wrapper after the base proxy is created. It therefore works with Trojan as well as VMess, VLESS, and other compatible stream-capable proxy adapters. On the server side, mihomo's Trojan listener uses the same sing-based special-destination handler as VMess and VLESS, sov1.mux.coolcarriers are accepted natively.For example:
Both endpoints must understand
mux.cool. A conventional Trojan server without thev1.mux.coolserver handler cannot terminate these carriers. The cross-runtime process matrix exercises VLESS against Xray-core for TCP, UDP, and XUDP in both directions. Trojan support is provided by the generic outbound wrapper and the shared Trojan listener handler, but does not yet have a dedicated two-process Trojan E2E test.Notes
Mux can introduce head-of-line blocking because multiple logical sessions share a TCP carrier. This affects both TCP streams and tunneled UDP/XUDP packets.
A dedicated UDP/XUDP packet pool isolates per-carrier TCP session capacity from long-lived packet sessions. Without
max-carriersit may increase the number of physical connections; withmax-carriersconfigured, both pools remain inside the shared cap.Pooled payload buffers are limited to internal carrier processing and are returned only after their consumer finishes. Public codec callers retain the original independent-memory behavior.
The feature is opt-in and disabled by default. UDP/443 is rejected by default when
mux.coolis enabled, matching Xray-core behavior.