From 837d7d885fb8b888db3aed9a2067c236ced76e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 23 Apr 2023 19:27:32 +0800 Subject: [PATCH] Add smux support --- app/proxyman/config.pb.go | 211 +++++++++++++++++++++++++------ app/proxyman/config.proto | 16 ++- app/proxyman/outbound/handler.go | 48 +++++++ common/mux/server.go | 16 +++ go.mod | 5 +- go.sum | 14 +- infra/conf/xray.go | 40 +++++- 7 files changed, 293 insertions(+), 57 deletions(-) diff --git a/app/proxyman/config.pb.go b/app/proxyman/config.pb.go index cd50e664..f3c68f09 100644 --- a/app/proxyman/config.pb.go +++ b/app/proxyman/config.pb.go @@ -524,6 +524,7 @@ type SenderConfig struct { StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"` ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"` MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"` + SmuxSettings *SingMultiplexConfig `protobuf:"bytes,5,opt,name=smux_settings,json=smuxSettings,proto3" json:"smux_settings,omitempty"` } func (x *SenderConfig) Reset() { @@ -586,6 +587,13 @@ func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig { return nil } +func (x *SenderConfig) GetSmuxSettings() *SingMultiplexConfig { + if x != nil { + return x.SmuxSettings + } + return nil +} + type MultiplexingConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -661,6 +669,93 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string { return "" } +type SingMultiplexConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Protocol string `protobuf:"bytes,2,opt,name=protocol,proto3" json:"protocol,omitempty"` + MaxConnections int32 `protobuf:"varint,3,opt,name=max_connections,json=maxConnections,proto3" json:"max_connections,omitempty"` + MinStreams int32 `protobuf:"varint,4,opt,name=min_streams,json=minStreams,proto3" json:"min_streams,omitempty"` + MaxStreams int32 `protobuf:"varint,5,opt,name=max_streams,json=maxStreams,proto3" json:"max_streams,omitempty"` + Padding bool `protobuf:"varint,6,opt,name=padding,proto3" json:"padding,omitempty"` +} + +func (x *SingMultiplexConfig) Reset() { + *x = SingMultiplexConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_app_proxyman_config_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SingMultiplexConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SingMultiplexConfig) ProtoMessage() {} + +func (x *SingMultiplexConfig) ProtoReflect() protoreflect.Message { + mi := &file_app_proxyman_config_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SingMultiplexConfig.ProtoReflect.Descriptor instead. +func (*SingMultiplexConfig) Descriptor() ([]byte, []int) { + return file_app_proxyman_config_proto_rawDescGZIP(), []int{8} +} + +func (x *SingMultiplexConfig) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *SingMultiplexConfig) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *SingMultiplexConfig) GetMaxConnections() int32 { + if x != nil { + return x.MaxConnections + } + return 0 +} + +func (x *SingMultiplexConfig) GetMinStreams() int32 { + if x != nil { + return x.MinStreams + } + return 0 +} + +func (x *SingMultiplexConfig) GetMaxStreams() int32 { + if x != nil { + return x.MaxStreams + } + return 0 +} + +func (x *SingMultiplexConfig) GetPadding() bool { + if x != nil { + return x.Padding + } + return false +} + type AllocationStrategy_AllocationStrategyConcurrency struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -672,7 +767,7 @@ type AllocationStrategy_AllocationStrategyConcurrency struct { func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() { *x = AllocationStrategy_AllocationStrategyConcurrency{} if protoimpl.UnsafeEnabled { - mi := &file_app_proxyman_config_proto_msgTypes[8] + mi := &file_app_proxyman_config_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -685,7 +780,7 @@ func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string { func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {} func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message { - mi := &file_app_proxyman_config_proto_msgTypes[8] + mi := &file_app_proxyman_config_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -719,7 +814,7 @@ type AllocationStrategy_AllocationStrategyRefresh struct { func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() { *x = AllocationStrategy_AllocationStrategyRefresh{} if protoimpl.UnsafeEnabled { - mi := &file_app_proxyman_config_proto_msgTypes[9] + mi := &file_app_proxyman_config_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -732,7 +827,7 @@ func (x *AllocationStrategy_AllocationStrategyRefresh) String() string { func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {} func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message { - mi := &file_app_proxyman_config_proto_msgTypes[9] + mi := &file_app_proxyman_config_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -855,7 +950,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{ 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02, 0x0a, 0x0c, 0x53, 0x65, + 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xfd, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, @@ -874,18 +969,36 @@ 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, 0xa4, 0x01, 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, 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, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, - 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, - 0x34, 0x34, 0x33, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, + 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0d, + 0x73, 0x6d, 0x75, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x4d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x65, 0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x73, 0x6d, 0x75, + 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xa4, 0x01, 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, 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, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, + 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, + 0x22, 0xd0, 0x01, 0x0a, 0x13, 0x53, 0x69, 0x6e, 0x67, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, + 0x65, 0x78, 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, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x27, + 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x69, + 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, + 0x61, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 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, @@ -909,7 +1022,7 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte { } var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_app_proxyman_config_proto_goTypes = []interface{}{ (KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols (AllocationStrategy_Type)(0), // 1: xray.app.proxyman.AllocationStrategy.Type @@ -921,35 +1034,37 @@ var file_app_proxyman_config_proto_goTypes = []interface{}{ (*OutboundConfig)(nil), // 7: xray.app.proxyman.OutboundConfig (*SenderConfig)(nil), // 8: xray.app.proxyman.SenderConfig (*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig - (*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency - (*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh - (*net.PortList)(nil), // 12: xray.common.net.PortList - (*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain - (*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig - (*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage - (*internet.ProxyConfig)(nil), // 16: xray.transport.internet.ProxyConfig + (*SingMultiplexConfig)(nil), // 10: xray.app.proxyman.SingMultiplexConfig + (*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency + (*AllocationStrategy_AllocationStrategyRefresh)(nil), // 12: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh + (*net.PortList)(nil), // 13: xray.common.net.PortList + (*net.IPOrDomain)(nil), // 14: xray.common.net.IPOrDomain + (*internet.StreamConfig)(nil), // 15: xray.transport.internet.StreamConfig + (*serial.TypedMessage)(nil), // 16: xray.common.serial.TypedMessage + (*internet.ProxyConfig)(nil), // 17: xray.transport.internet.ProxyConfig } var file_app_proxyman_config_proto_depIdxs = []int32{ 1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type - 10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency - 11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh - 12, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList - 13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain + 11, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency + 12, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh + 13, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList + 14, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy - 14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig + 15, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols 4, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig - 15, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage - 15, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage - 13, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain - 14, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig - 16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig + 16, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage + 16, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage + 14, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain + 15, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig + 17, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig 9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig - 15, // [15:15] is the sub-list for method output_type - 15, // [15:15] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 10, // 15: xray.app.proxyman.SenderConfig.smux_settings:type_name -> xray.app.proxyman.SingMultiplexConfig + 16, // [16:16] is the sub-list for method output_type + 16, // [16:16] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name } func init() { file_app_proxyman_config_proto_init() } @@ -1055,7 +1170,7 @@ func file_app_proxyman_config_proto_init() { } } file_app_proxyman_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AllocationStrategy_AllocationStrategyConcurrency); i { + switch v := v.(*SingMultiplexConfig); i { case 0: return &v.state case 1: @@ -1067,6 +1182,18 @@ func file_app_proxyman_config_proto_init() { } } file_app_proxyman_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AllocationStrategy_AllocationStrategyConcurrency); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_app_proxyman_config_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AllocationStrategy_AllocationStrategyRefresh); i { case 0: return &v.state @@ -1085,7 +1212,7 @@ func file_app_proxyman_config_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_app_proxyman_config_proto_rawDesc, NumEnums: 2, - NumMessages: 10, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/app/proxyman/config.proto b/app/proxyman/config.proto index 5d063eba..dcfb30cd 100644 --- a/app/proxyman/config.proto +++ b/app/proxyman/config.proto @@ -27,13 +27,13 @@ message AllocationStrategy { Type type = 1; - message AllocationStrategyConcurrency { uint32 value = 1; } + message AllocationStrategyConcurrency {uint32 value = 1;} // Number of handlers (ports) running in parallel. // Default value is 3 if unset. AllocationStrategyConcurrency concurrency = 2; - message AllocationStrategyRefresh { uint32 value = 1; } + message AllocationStrategyRefresh {uint32 value = 1;} // Number of minutes before a handler is regenerated. // Default value is 5 if unset. @@ -73,7 +73,7 @@ message ReceiverConfig { reserved 6; // Override domains for the given protocol. // Deprecated. Use sniffing_settings. - repeated KnownProtocols domain_override = 7 [ deprecated = true ]; + repeated KnownProtocols domain_override = 7 [deprecated = true]; SniffingConfig sniffing_settings = 8; } @@ -91,6 +91,7 @@ message SenderConfig { xray.transport.internet.StreamConfig stream_settings = 2; xray.transport.internet.ProxyConfig proxy_settings = 3; MultiplexingConfig multiplex_settings = 4; + SingMultiplexConfig smux_settings = 5; } message MultiplexingConfig { @@ -103,3 +104,12 @@ message MultiplexingConfig { // "reject" (default), "allow" or "skip". string xudpProxyUDP443 = 4; } + +message SingMultiplexConfig { + bool enabled = 1; + string protocol = 2; + int32 max_connections = 3; + int32 min_streams = 4; + int32 max_streams = 5; + bool padding = 6; +} diff --git a/app/proxyman/outbound/handler.go b/app/proxyman/outbound/handler.go index b477dd6b..ed39aa6a 100644 --- a/app/proxyman/outbound/handler.go +++ b/app/proxyman/outbound/handler.go @@ -6,12 +6,15 @@ import ( "io" "os" + sing_mux "github.com/sagernet/sing-mux" + sing_net "github.com/sagernet/sing/common/network" "github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/session" + "github.com/xtls/xray-core/common/singbridge" "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/policy" @@ -58,6 +61,8 @@ type Handler struct { outboundManager outbound.Manager mux *mux.ClientManager xudp *mux.ClientManager + smux *sing_mux.Client + udp443 string uplinkCounter stats.Counter downlinkCounter stats.Counter @@ -154,6 +159,21 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou h.udp443 = config.XudpProxyUDP443 } } + if h.senderSettings != nil && h.senderSettings.SmuxSettings != nil { + if config := h.senderSettings.SmuxSettings; config.Enabled { + h.smux, err = sing_mux.NewClient(sing_mux.Options{ + Dialer: singbridge.NewOutboundDialer(proxyHandler, h), + Protocol: config.Protocol, + MaxConnections: int(config.MaxConnections), + MinStreams: int(config.MinStreams), + MaxStreams: int(config.MaxStreams), + Padding: config.Padding, + }) + if err != nil { + return nil, newError("failed to create sing mux client").Base(err) + } + } + } h.proxy = proxyHandler return h, nil @@ -197,6 +217,34 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { return } } + if h.smux != 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) + } + } + inbound := session.InboundFromContext(ctx) + outbound := session.OutboundFromContext(ctx) + if outbound.Target.Network == net.Network_TCP { + conn, err := h.smux.DialContext(ctx, sing_net.NetworkTCP, singbridge.ToSocksaddr(outbound.Target)) + if err != nil { + test(err) + return + } + test(singbridge.CopyConn(ctx, inbound.Conn, link, conn)) + } else { + packetConn, err := h.smux.ListenPacket(ctx, singbridge.ToSocksaddr(outbound.Target)) + if err != nil { + test(err) + return + } + test(singbridge.CopyPacketConn(ctx, inbound.Conn, link, outbound.Target, packetConn)) + } + return + } out: err := h.proxy.Process(ctx, link, h) if err != nil { diff --git a/common/mux/server.go b/common/mux/server.go index 2d33189f..00457c6a 100644 --- a/common/mux/server.go +++ b/common/mux/server.go @@ -4,13 +4,17 @@ import ( "context" "io" + sing_mux "github.com/sagernet/sing-mux" + "github.com/sagernet/sing/common/metadata" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/net" + "github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/session" + "github.com/xtls/xray-core/common/singbridge" "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/transport" @@ -38,6 +42,14 @@ func (s *Server) Type() interface{} { // Dispatch implements routing.Dispatcher func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) { if dest.Address != muxCoolAddress { + if dest.Address.Family() == net.AddressFamilyDomain && dest.Address.Domain() == sing_mux.Destination.Fqdn { + opts := pipe.OptionsFromContext(ctx) + uplinkReader, uplinkWriter := pipe.New(opts...) + downlinkReader, downlinkWriter := pipe.New(opts...) + conn := cnc.NewConnection(cnc.ConnectionInputMulti(downlinkWriter), cnc.ConnectionOutputMulti(uplinkReader)) + go sing_mux.HandleConnection(ctx, singbridge.NewDispatcher(s.dispatcher, newError), singbridge.NewLogger(newError), conn, metadata.Metadata{Destination: singbridge.ToSocksaddr(dest)}) + return &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil + } return s.dispatcher.Dispatch(ctx, dest) } @@ -59,6 +71,10 @@ func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport // DispatchLink implements routing.Dispatcher func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error { if dest.Address != muxCoolAddress { + if dest.Address.Family() == net.AddressFamilyDomain && dest.Address.Domain() == sing_mux.Destination.Fqdn { + conn := cnc.NewConnection(cnc.ConnectionInputMulti(link.Writer), cnc.ConnectionOutputMulti(link.Reader)) + return sing_mux.HandleConnection(ctx, singbridge.NewDispatcher(s.dispatcher, newError), singbridge.NewLogger(newError), conn, metadata.Metadata{Destination: singbridge.ToSocksaddr(dest)}) + } return s.dispatcher.DispatchLink(ctx, dest, link) } _, err := NewServerWorker(ctx, s.dispatcher, link) diff --git a/go.mod b/go.mod index bf6a6c3a..33152495 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,8 @@ require ( github.com/pires/go-proxyproto v0.7.0 github.com/quic-go/quic-go v0.34.0 github.com/refraction-networking/utls v1.3.2 - github.com/sagernet/sing v0.2.4 + github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 + github.com/sagernet/sing-mux v0.0.0-20230424061035-f6a6b7258c29 github.com/sagernet/sing-shadowsocks v0.2.1 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb @@ -41,6 +42,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/onsi/ginkgo/v2 v2.9.2 // indirect @@ -48,6 +50,7 @@ require ( github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect + github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/mod v0.10.0 // indirect diff --git a/go.sum b/go.sum index f8df0400..43fe5937 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI= github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -143,12 +145,15 @@ github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvj github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk= -github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo= -github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 h1:+dDVjW20IT+e8maKryaDeRY2+RFmTFdrQeIzqE2WOss= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.0.0-20230424061035-f6a6b7258c29 h1:JqNg7xbPHV7YtQFiaqYTRY79fjonNN8u4GMf4T6Lb3E= +github.com/sagernet/sing-mux v0.0.0-20230424061035-f6a6b7258c29/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw= github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I= +github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= +github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= @@ -257,6 +262,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/infra/conf/xray.go b/infra/conf/xray.go index 8b6d05f4..33a45232 100644 --- a/infra/conf/xray.go +++ b/infra/conf/xray.go @@ -130,6 +130,24 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) { }, nil } +type SingMuxConfig struct { + Enabled bool `json:"enabled"` + Protocol string `json:"protocol"` + MaxConnections int `json:"max_connections"` + MinStreams int `json:"min_streams"` + MaxStreams int `json:"max_streams"` +} + +func (m *SingMuxConfig) Build() (*proxyman.SingMultiplexConfig, error) { + return &proxyman.SingMultiplexConfig{ + Enabled: m.Enabled, + Protocol: m.Protocol, + MaxConnections: int32(m.MaxConnections), + MinStreams: int32(m.MinStreams), + MaxStreams: int32(m.MaxStreams), + }, nil +} + type InboundDetourAllocationConfig struct { Strategy string `json:"strategy"` Concurrency *uint32 `json:"concurrency"` @@ -278,13 +296,14 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) { } type OutboundDetourConfig struct { - Protocol string `json:"protocol"` - SendThrough *Address `json:"sendThrough"` - Tag string `json:"tag"` - Settings *json.RawMessage `json:"settings"` - StreamSetting *StreamConfig `json:"streamSettings"` - ProxySettings *ProxyConfig `json:"proxySettings"` - MuxSettings *MuxConfig `json:"mux"` + Protocol string `json:"protocol"` + SendThrough *Address `json:"sendThrough"` + Tag string `json:"tag"` + Settings *json.RawMessage `json:"settings"` + StreamSetting *StreamConfig `json:"streamSettings"` + ProxySettings *ProxyConfig `json:"proxySettings"` + MuxSettings *MuxConfig `json:"mux"` + SingMuxSettings *SingMuxConfig `json:"smux"` } func (c *OutboundDetourConfig) checkChainProxyConfig() error { @@ -347,6 +366,13 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) { } senderSettings.MultiplexSettings = ms } + if c.SingMuxSettings != nil { + ms, err := c.SingMuxSettings.Build() + if err != nil { + return nil, newError("failed to build sing-mux config.").Base(err) + } + senderSettings.SmuxSettings = ms + } settings := []byte("{}") if c.Settings != nil {