diff --git a/app/proxyman/config.pb.go b/app/proxyman/config.pb.go index c3b221c4..664e6670 100644 --- a/app/proxyman/config.pb.go +++ b/app/proxyman/config.pb.go @@ -594,9 +594,9 @@ type MultiplexingConfig struct { // Whether or not Mux is enabled. Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` // Max number of concurrent connections that one Mux connection can handle. - Concurrency uint32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"` - // Both(0), TCP(net.Network_TCP), UDP(net.Network_UDP). - Only uint32 `protobuf:"varint,3,opt,name=only,proto3" json:"only,omitempty"` + Concurrency int32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"` + // Transport XUDP in another Mux. + XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"` } func (x *MultiplexingConfig) Reset() { @@ -638,16 +638,16 @@ func (x *MultiplexingConfig) GetEnabled() bool { return false } -func (x *MultiplexingConfig) GetConcurrency() uint32 { +func (x *MultiplexingConfig) GetConcurrency() int32 { if x != nil { return x.Concurrency } return 0 } -func (x *MultiplexingConfig) GetOnly() uint32 { +func (x *MultiplexingConfig) GetXudpConcurrency() int32 { if x != nil { - return x.Only + return x.XudpConcurrency } return 0 } @@ -865,22 +865,23 @@ var file_app_proxyman_config_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, - 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x64, 0x0a, 0x12, + 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x7a, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, - 0x0a, 0x04, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6f, 0x6e, - 0x6c, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, - 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, - 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, - 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, - 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, - 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, - 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, + 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, + 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, + 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, + 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, + 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, + 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/proxyman/config.proto b/app/proxyman/config.proto index 8f282aa2..dc755fef 100644 --- a/app/proxyman/config.proto +++ b/app/proxyman/config.proto @@ -97,7 +97,7 @@ message MultiplexingConfig { // Whether or not Mux is enabled. bool enabled = 1; // Max number of concurrent connections that one Mux connection can handle. - uint32 concurrency = 2; - // Both(0), TCP(net.Network_TCP), UDP(net.Network_UDP). - uint32 only = 3; + int32 concurrency = 2; + // Transport XUDP in another Mux. + int32 xudpConcurrency = 3; } diff --git a/app/proxyman/outbound/handler.go b/app/proxyman/outbound/handler.go index 89e2862d..4de70df2 100644 --- a/app/proxyman/outbound/handler.go +++ b/app/proxyman/outbound/handler.go @@ -57,6 +57,7 @@ type Handler struct { proxy proxy.Outbound outboundManager outbound.Manager mux *mux.ClientManager + xudp *mux.ClientManager uplinkCounter stats.Counter downlinkCounter stats.Counter } @@ -106,23 +107,49 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou } if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil { - config := h.senderSettings.MultiplexSettings - if config.Concurrency < 1 || config.Concurrency > 1024 { - return nil, newError("invalid mux concurrency: ", config.Concurrency).AtWarning() - } - h.mux = &mux.ClientManager{ - Enabled: config.Enabled, - Picker: &mux.IncrementalWorkerPicker{ - Factory: &mux.DialingWorkerFactory{ - Proxy: proxyHandler, - Dialer: h, - Strategy: mux.ClientStrategy{ - MaxConcurrency: config.Concurrency, - MaxConnection: 128, + if config := h.senderSettings.MultiplexSettings; config.Enabled { + if config.Concurrency < 0 { + h.mux = &mux.ClientManager{Enabled: false} + } + if config.Concurrency == 0 { + config.Concurrency = 8 // same as before + } + if config.Concurrency > 0 { + h.mux = &mux.ClientManager{ + Enabled: true, + Picker: &mux.IncrementalWorkerPicker{ + Factory: &mux.DialingWorkerFactory{ + Proxy: proxyHandler, + Dialer: h, + Strategy: mux.ClientStrategy{ + MaxConcurrency: uint32(config.Concurrency), + MaxConnection: 128, + }, + }, }, - }, - }, - Only: config.Only, + } + } + if config.XudpConcurrency < 0 { + h.xudp = &mux.ClientManager{Enabled: false} + } + if config.XudpConcurrency == 0 { + h.xudp = nil // same as before + } + if config.XudpConcurrency > 0 { + h.xudp = &mux.ClientManager{ + Enabled: true, + Picker: &mux.IncrementalWorkerPicker{ + Factory: &mux.DialingWorkerFactory{ + Proxy: proxyHandler, + Dialer: h, + Strategy: mux.ClientStrategy{ + MaxConcurrency: uint32(config.XudpConcurrency), + MaxConnection: 128, + }, + }, + }, + } + } } } @@ -137,33 +164,44 @@ func (h *Handler) Tag() string { // Dispatch implements proxy.Outbound.Dispatch. func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { - outbound := session.OutboundFromContext(ctx) - if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) && - (h.mux.Only == 0 || (outbound != nil && h.mux.Only == uint32(outbound.Target.Network))) { - if err := h.mux.Dispatch(ctx, link); err != nil { - err := newError("failed to process mux outbound traffic").Base(err) - session.SubmitOutboundErrorToOriginator(ctx, err) - err.WriteToLog(session.ExportIDToError(ctx)) - common.Interrupt(link.Writer) - } - } else { - err := h.proxy.Process(ctx, link, h) - if err != nil { - if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) { - err = nil + if h.mux != nil { + test := func(err error) { + if err != nil { + err := newError("failed to process mux outbound traffic").Base(err) + session.SubmitOutboundErrorToOriginator(ctx, err) + err.WriteToLog(session.ExportIDToError(ctx)) + common.Interrupt(link.Writer) } } - if err != nil { - // Ensure outbound ray is properly closed. - err := newError("failed to process outbound traffic").Base(err) - session.SubmitOutboundErrorToOriginator(ctx, err) - err.WriteToLog(session.ExportIDToError(ctx)) - common.Interrupt(link.Writer) - } else { - common.Must(common.Close(link.Writer)) + if h.xudp != nil && session.OutboundFromContext(ctx).Target.Network == net.Network_UDP { + if !h.xudp.Enabled { + goto out + } + test(h.xudp.Dispatch(ctx, link)) + return + } + if h.mux.Enabled { + test(h.mux.Dispatch(ctx, link)) + return } - common.Interrupt(link.Reader) } +out: + err := h.proxy.Process(ctx, link, h) + if err != nil { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) { + err = nil + } + } + if err != nil { + // Ensure outbound ray is properly closed. + err := newError("failed to process outbound traffic").Base(err) + session.SubmitOutboundErrorToOriginator(ctx, err) + err.WriteToLog(session.ExportIDToError(ctx)) + common.Interrupt(link.Writer) + } else { + common.Must(common.Close(link.Writer)) + } + common.Interrupt(link.Reader) } // Address implements internet.Dialer. diff --git a/common/mux/client.go b/common/mux/client.go index f933ef4c..88621be0 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -24,7 +24,6 @@ import ( type ClientManager struct { Enabled bool // wheather mux is enabled from user config Picker WorkerPicker - Only uint32 } func (m *ClientManager) Dispatch(ctx context.Context, link *transport.Link) error { diff --git a/infra/conf/xray.go b/infra/conf/xray.go index 63ffccf5..07c667fe 100644 --- a/infra/conf/xray.go +++ b/infra/conf/xray.go @@ -10,7 +10,6 @@ import ( "github.com/xtls/xray-core/app/dispatcher" "github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/stats" - "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/serial" core "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/transport/internet" @@ -108,36 +107,18 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) { } type MuxConfig struct { - Enabled bool `json:"enabled"` - Concurrency int16 `json:"concurrency"` - Only string `json:"only"` + Enabled bool `json:"enabled"` + Concurrency int16 `json:"concurrency"` + XudpConcurrency int16 `json:"xudpConcurrency"` } // Build creates MultiplexingConfig, Concurrency < 0 completely disables mux. func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) { - if m.Concurrency < 0 { - return nil, nil - } - if m.Concurrency == 0 { - m.Concurrency = 8 - } - - config := &proxyman.MultiplexingConfig{ - Enabled: m.Enabled, - Concurrency: uint32(m.Concurrency), - } - - switch strings.ToLower(m.Only) { - case "", "both": - case "tcp": - config.Only = uint32(net.Network_TCP) - case "udp": - config.Only = uint32(net.Network_UDP) - default: - return nil, newError(`unknown "only": `, m.Only) - } - - return config, nil + return &proxyman.MultiplexingConfig{ + Enabled: m.Enabled, + Concurrency: int32(m.Concurrency), + XudpConcurrency: int32(m.XudpConcurrency), + }, nil } type InboundDetourAllocationConfig struct { diff --git a/infra/conf/xray_test.go b/infra/conf/xray_test.go index 02d868fe..91b82eea 100644 --- a/infra/conf/xray_test.go +++ b/infra/conf/xray_test.go @@ -345,13 +345,16 @@ func TestMuxConfig_Build(t *testing.T) { }}, {"empty def", `{}`, &proxyman.MultiplexingConfig{ Enabled: false, - Concurrency: 8, + Concurrency: 0, }}, {"not enable", `{"enabled": false, "concurrency": 4}`, &proxyman.MultiplexingConfig{ Enabled: false, Concurrency: 4, }}, - {"forbidden", `{"enabled": false, "concurrency": -1}`, nil}, + {"forbidden", `{"enabled": false, "concurrency": -1}`, &proxyman.MultiplexingConfig{ + Enabled: false, + Concurrency: -1, + }}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {