mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-11-13 21:52:50 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc7a3c14d7 |
@@ -2,6 +2,7 @@ package dispatcher
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
go_errors "errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -488,6 +489,12 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
|
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if !go_errors.Is(err, common.ErrNoClue) {
|
||||||
|
errors.LogWarningInner(ctx, err, "get error during route pick ")
|
||||||
|
common.Close(link.Writer)
|
||||||
|
common.Interrupt(link.Reader)
|
||||||
|
return
|
||||||
|
}
|
||||||
errors.LogInfo(ctx, "default route for ", destination)
|
errors.LogInfo(ctx, "default route for ", destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,23 @@
|
|||||||
package proxyman
|
package proxyman
|
||||||
|
|
||||||
|
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
|
||||||
|
if s == nil || s.Concurrency == nil {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
return s.Concurrency.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AllocationStrategy) GetRefreshValue() uint32 {
|
||||||
|
if s == nil || s.Refresh == nil {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
return s.Refresh.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
|
||||||
|
if c.SniffingSettings != nil {
|
||||||
|
return c.SniffingSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+400
-143
@@ -23,6 +23,58 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AllocationStrategy_Type int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
AllocationStrategy_Always AllocationStrategy_Type = 0
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
AllocationStrategy_Random AllocationStrategy_Type = 1
|
||||||
|
// External. Not supported yet.
|
||||||
|
AllocationStrategy_External AllocationStrategy_Type = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for AllocationStrategy_Type.
|
||||||
|
var (
|
||||||
|
AllocationStrategy_Type_name = map[int32]string{
|
||||||
|
0: "Always",
|
||||||
|
1: "Random",
|
||||||
|
2: "External",
|
||||||
|
}
|
||||||
|
AllocationStrategy_Type_value = map[string]int32{
|
||||||
|
"Always": 0,
|
||||||
|
"Random": 1,
|
||||||
|
"External": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {
|
||||||
|
p := new(AllocationStrategy_Type)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_proxyman_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_Type.Descriptor instead.
|
||||||
|
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
type InboundConfig struct {
|
type InboundConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -59,6 +111,71 @@ func (*InboundConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.proxyman.AllocationStrategy_Type" json:"type,omitempty"`
|
||||||
|
// Number of handlers (ports) running in parallel.
|
||||||
|
// Default value is 3 if unset.
|
||||||
|
Concurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
Refresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh,proto3" json:"refresh,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) Reset() {
|
||||||
|
*x = AllocationStrategy{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetType() AllocationStrategy_Type {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return AllocationStrategy_Always
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {
|
||||||
|
if x != nil {
|
||||||
|
return x.Concurrency
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {
|
||||||
|
if x != nil {
|
||||||
|
return x.Refresh
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type SniffingConfig struct {
|
type SniffingConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -79,7 +196,7 @@ type SniffingConfig struct {
|
|||||||
|
|
||||||
func (x *SniffingConfig) Reset() {
|
func (x *SniffingConfig) Reset() {
|
||||||
*x = SniffingConfig{}
|
*x = SniffingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -91,7 +208,7 @@ func (x *SniffingConfig) String() string {
|
|||||||
func (*SniffingConfig) ProtoMessage() {}
|
func (*SniffingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -104,7 +221,7 @@ func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetEnabled() bool {
|
func (x *SniffingConfig) GetEnabled() bool {
|
||||||
@@ -151,14 +268,15 @@ type ReceiverConfig struct {
|
|||||||
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
|
||||||
ReceiveOriginalDestination bool `protobuf:"varint,4,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
SniffingSettings *SniffingConfig `protobuf:"bytes,6,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
||||||
|
SniffingSettings *SniffingConfig `protobuf:"bytes,7,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) Reset() {
|
func (x *ReceiverConfig) Reset() {
|
||||||
*x = ReceiverConfig{}
|
*x = ReceiverConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -170,7 +288,7 @@ func (x *ReceiverConfig) String() string {
|
|||||||
func (*ReceiverConfig) ProtoMessage() {}
|
func (*ReceiverConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -183,7 +301,7 @@ func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
||||||
@@ -200,6 +318,13 @@ func (x *ReceiverConfig) GetListen() *net.IPOrDomain {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllocationStrategy
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.StreamSettings
|
return x.StreamSettings
|
||||||
@@ -233,7 +358,7 @@ type InboundHandlerConfig struct {
|
|||||||
|
|
||||||
func (x *InboundHandlerConfig) Reset() {
|
func (x *InboundHandlerConfig) Reset() {
|
||||||
*x = InboundHandlerConfig{}
|
*x = InboundHandlerConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -245,7 +370,7 @@ func (x *InboundHandlerConfig) String() string {
|
|||||||
func (*InboundHandlerConfig) ProtoMessage() {}
|
func (*InboundHandlerConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -258,7 +383,7 @@ func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) GetTag() string {
|
func (x *InboundHandlerConfig) GetTag() string {
|
||||||
@@ -290,7 +415,7 @@ type OutboundConfig struct {
|
|||||||
|
|
||||||
func (x *OutboundConfig) Reset() {
|
func (x *OutboundConfig) Reset() {
|
||||||
*x = OutboundConfig{}
|
*x = OutboundConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -302,7 +427,7 @@ func (x *OutboundConfig) String() string {
|
|||||||
func (*OutboundConfig) ProtoMessage() {}
|
func (*OutboundConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -315,7 +440,7 @@ func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SenderConfig struct {
|
type SenderConfig struct {
|
||||||
@@ -334,7 +459,7 @@ type SenderConfig struct {
|
|||||||
|
|
||||||
func (x *SenderConfig) Reset() {
|
func (x *SenderConfig) Reset() {
|
||||||
*x = SenderConfig{}
|
*x = SenderConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -346,7 +471,7 @@ func (x *SenderConfig) String() string {
|
|||||||
func (*SenderConfig) ProtoMessage() {}
|
func (*SenderConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -359,7 +484,7 @@ func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
||||||
@@ -421,7 +546,7 @@ type MultiplexingConfig struct {
|
|||||||
|
|
||||||
func (x *MultiplexingConfig) Reset() {
|
func (x *MultiplexingConfig) Reset() {
|
||||||
*x = MultiplexingConfig{}
|
*x = MultiplexingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -433,7 +558,7 @@ func (x *MultiplexingConfig) String() string {
|
|||||||
func (*MultiplexingConfig) ProtoMessage() {}
|
func (*MultiplexingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -446,7 +571,7 @@ func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetEnabled() bool {
|
func (x *MultiplexingConfig) GetEnabled() bool {
|
||||||
@@ -477,6 +602,96 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyConcurrency struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyConcurrency{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyRefresh struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyRefresh{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_proxyman_config_proto_rawDesc = []byte{
|
var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||||
@@ -491,98 +706,130 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||||||
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
|
0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||||
0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74,
|
||||||
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c,
|
||||||
0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
|
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72,
|
0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63,
|
||||||
0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x5f,
|
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f,
|
0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12,
|
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
|
||||||
0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x79,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72,
|
||||||
0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x6e,
|
0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||||
0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x4f,
|
0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20,
|
||||||
0x6e, 0x6c, 0x79, 0x22, 0xe5, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
|
0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c,
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33,
|
0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a,
|
||||||
0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
|
0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14,
|
||||||
0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73,
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76,
|
||||||
0x74, 0x65, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65,
|
0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
|
0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e,
|
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||||
0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69,
|
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
||||||
0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f,
|
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
||||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69,
|
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||||
0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
|
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||||
0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
|
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||||
0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
|
||||||
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73,
|
||||||
0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74,
|
0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0xc0, 0x01, 0x0a, 0x14,
|
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
|
||||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f,
|
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76,
|
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
|
||||||
0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||||
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
|
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
||||||
0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74,
|
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73,
|
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
|
||||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
|
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
|
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
||||||
0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10,
|
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
|
||||||
0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
|
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61,
|
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
||||||
0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
|
||||||
0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
||||||
0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
|
||||||
0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
||||||
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
|
||||||
0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d,
|
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
|
||||||
0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a,
|
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
|
||||||
0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
|
||||||
|
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
|
||||||
|
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
|
||||||
|
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
|
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||||
|
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
||||||
|
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
||||||
|
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x63, 0x6f, 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, 0x10, 0x72, 0x65,
|
||||||
|
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
|
||||||
|
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
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, 0x9d, 0x03, 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,
|
||||||
|
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||||
|
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||||
|
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
|
||||||
|
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
||||||
|
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
|
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||||
|
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
|
||||||
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
||||||
|
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||||
|
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, 0x12, 0x19, 0x0a, 0x08,
|
||||||
|
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||||
|
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||||
|
0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
|
||||||
|
0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
|
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
|
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||||
|
0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75,
|
||||||
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
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,
|
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18,
|
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f,
|
||||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50,
|
0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f,
|
||||||
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
|
0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||||
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75,
|
||||||
0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72,
|
||||||
0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
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,
|
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,
|
0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||||
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50,
|
||||||
0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -597,39 +844,48 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_proxyman_config_proto_rawDescData
|
return file_app_proxyman_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_app_proxyman_config_proto_goTypes = []any{
|
var file_app_proxyman_config_proto_goTypes = []any{
|
||||||
(*InboundConfig)(nil), // 0: xray.app.proxyman.InboundConfig
|
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type
|
||||||
(*SniffingConfig)(nil), // 1: xray.app.proxyman.SniffingConfig
|
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig
|
||||||
(*ReceiverConfig)(nil), // 2: xray.app.proxyman.ReceiverConfig
|
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
|
||||||
(*InboundHandlerConfig)(nil), // 3: xray.app.proxyman.InboundHandlerConfig
|
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
|
||||||
(*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig
|
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
|
||||||
(*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
|
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
|
||||||
(*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
|
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
|
||||||
(*net.PortList)(nil), // 7: xray.common.net.PortList
|
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
|
||||||
(*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
|
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
|
||||||
(*internet.StreamConfig)(nil), // 9: xray.transport.internet.StreamConfig
|
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage
|
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
(*internet.ProxyConfig)(nil), // 11: xray.transport.internet.ProxyConfig
|
(*net.PortList)(nil), // 11: xray.common.net.PortList
|
||||||
(internet.DomainStrategy)(0), // 12: xray.transport.internet.DomainStrategy
|
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
||||||
|
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
||||||
|
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
||||||
|
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
||||||
|
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
|
||||||
}
|
}
|
||||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||||
7, // 0: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||||
8, // 1: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
9, // 2: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
1, // 3: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
||||||
10, // 4: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||||
10, // 5: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
|
||||||
8, // 6: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
9, // 7: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||||
11, // 8: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
6, // 9: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
12, // 10: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||||
11, // [11:11] is the sub-list for method output_type
|
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
11, // [11:11] is the sub-list for method input_type
|
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||||
11, // [11:11] is the sub-list for extension type_name
|
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
11, // [11:11] is the sub-list for extension extendee
|
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
0, // [0:11] is the sub-list for field type_name
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
@@ -642,13 +898,14 @@ func file_app_proxyman_config_proto_init() {
|
|||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
|
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 7,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_app_proxyman_config_proto_goTypes,
|
GoTypes: file_app_proxyman_config_proto_goTypes,
|
||||||
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_app_proxyman_config_proto_enumTypes,
|
||||||
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_proxyman_config_proto = out.File
|
File_app_proxyman_config_proto = out.File
|
||||||
|
|||||||
@@ -13,6 +13,33 @@ import "common/serial/typed_message.proto";
|
|||||||
|
|
||||||
message InboundConfig {}
|
message InboundConfig {}
|
||||||
|
|
||||||
|
message AllocationStrategy {
|
||||||
|
enum Type {
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
Always = 0;
|
||||||
|
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
Random = 1;
|
||||||
|
|
||||||
|
// External. Not supported yet.
|
||||||
|
External = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = 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; }
|
||||||
|
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
AllocationStrategyRefresh refresh = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message SniffingConfig {
|
message SniffingConfig {
|
||||||
// Whether or not to enable content sniffing on an inbound connection.
|
// Whether or not to enable content sniffing on an inbound connection.
|
||||||
bool enabled = 1;
|
bool enabled = 1;
|
||||||
@@ -35,10 +62,11 @@ message ReceiverConfig {
|
|||||||
xray.common.net.PortList port_list = 1;
|
xray.common.net.PortList port_list = 1;
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
xray.common.net.IPOrDomain listen = 2;
|
xray.common.net.IPOrDomain listen = 2;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 3;
|
AllocationStrategy allocation_strategy = 3;
|
||||||
bool receive_original_destination = 4;
|
xray.transport.internet.StreamConfig stream_settings = 4;
|
||||||
reserved 5;
|
bool receive_original_destination = 5;
|
||||||
SniffingConfig sniffing_settings = 6;
|
reserved 6;
|
||||||
|
SniffingConfig sniffing_settings = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InboundHandlerConfig {
|
message InboundHandlerConfig {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -102,7 +103,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
stream: mss,
|
stream: mss,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -124,7 +125,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -139,7 +140,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
address: address,
|
address: address,
|
||||||
port: net.Port(port),
|
port: net.Port(port),
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
stream: mss,
|
stream: mss,
|
||||||
@@ -177,6 +178,14 @@ func (h *AlwaysOnInboundHandler) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
if len(h.workers) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.workers[dice.Roll(len(h.workers))]
|
||||||
|
return w.Proxy(), w.Port(), 9999
|
||||||
|
}
|
||||||
|
|
||||||
func (h *AlwaysOnInboundHandler) Tag() string {
|
func (h *AlwaysOnInboundHandler) Tag() string {
|
||||||
return h.tag
|
return h.tag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/mux"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
|
"github.com/xtls/xray-core/core"
|
||||||
|
"github.com/xtls/xray-core/proxy"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DynamicInboundHandler struct {
|
||||||
|
tag string
|
||||||
|
v *core.Instance
|
||||||
|
proxyConfig interface{}
|
||||||
|
receiverConfig *proxyman.ReceiverConfig
|
||||||
|
streamSettings *internet.MemoryStreamConfig
|
||||||
|
portMutex sync.Mutex
|
||||||
|
portsInUse map[net.Port]struct{}
|
||||||
|
workerMutex sync.RWMutex
|
||||||
|
worker []worker
|
||||||
|
lastRefresh time.Time
|
||||||
|
mux *mux.Server
|
||||||
|
task *task.Periodic
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
|
||||||
|
v := core.MustFromContext(ctx)
|
||||||
|
h := &DynamicInboundHandler{
|
||||||
|
tag: tag,
|
||||||
|
proxyConfig: proxyConfig,
|
||||||
|
receiverConfig: receiverConfig,
|
||||||
|
portsInUse: make(map[net.Port]struct{}),
|
||||||
|
mux: mux.NewServer(ctx),
|
||||||
|
v: v,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
|
if mss.SocketSettings == nil {
|
||||||
|
mss.SocketSettings = &internet.SocketConfig{}
|
||||||
|
}
|
||||||
|
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
|
||||||
|
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
|
||||||
|
}
|
||||||
|
mss.SocketSettings.ReceiveOriginalDestAddress = true
|
||||||
|
}
|
||||||
|
|
||||||
|
h.streamSettings = mss
|
||||||
|
|
||||||
|
h.task = &task.Periodic{
|
||||||
|
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
|
||||||
|
Execute: h.refresh,
|
||||||
|
}
|
||||||
|
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) allocatePort() net.Port {
|
||||||
|
allPorts := []int32{}
|
||||||
|
for _, pr := range h.receiverConfig.PortList.Range {
|
||||||
|
for i := pr.From; i <= pr.To; i++ {
|
||||||
|
allPorts = append(allPorts, int32(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.portMutex.Lock()
|
||||||
|
defer h.portMutex.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
r := dice.Roll(len(allPorts))
|
||||||
|
port := net.Port(allPorts[r])
|
||||||
|
_, used := h.portsInUse[port]
|
||||||
|
if !used {
|
||||||
|
h.portsInUse[port] = struct{}{}
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
||||||
|
ports2Del := make([]net.Port, len(workers))
|
||||||
|
for idx, worker := range workers {
|
||||||
|
ports2Del[idx] = worker.Port()
|
||||||
|
if err := worker.Close(); err != nil {
|
||||||
|
errors.LogInfoInner(h.ctx, err, "failed to close worker")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.portMutex.Lock()
|
||||||
|
for _, port := range ports2Del {
|
||||||
|
delete(h.portsInUse, port)
|
||||||
|
}
|
||||||
|
h.portMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) refresh() error {
|
||||||
|
h.lastRefresh = time.Now()
|
||||||
|
|
||||||
|
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
|
||||||
|
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
|
||||||
|
workers := make([]worker, 0, concurrency)
|
||||||
|
|
||||||
|
address := h.receiverConfig.Listen.AsAddress()
|
||||||
|
if address == nil {
|
||||||
|
address = net.AnyIP
|
||||||
|
}
|
||||||
|
|
||||||
|
uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
|
||||||
|
|
||||||
|
for i := uint32(0); i < concurrency; i++ {
|
||||||
|
port := h.allocatePort()
|
||||||
|
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := rawProxy.(proxy.Inbound)
|
||||||
|
nl := p.Network()
|
||||||
|
if net.HasNetwork(nl, net.Network_TCP) {
|
||||||
|
worker := &tcpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
proxy: p,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.HasNetwork(nl, net.Network_UDP) {
|
||||||
|
worker := &udpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
proxy: p,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.workerMutex.Lock()
|
||||||
|
h.worker = workers
|
||||||
|
h.workerMutex.Unlock()
|
||||||
|
|
||||||
|
time.AfterFunc(timeout, func() {
|
||||||
|
h.closeWorkers(workers)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Start() error {
|
||||||
|
return h.task.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Close() error {
|
||||||
|
return h.task.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
h.workerMutex.RLock()
|
||||||
|
defer h.workerMutex.RUnlock()
|
||||||
|
|
||||||
|
if len(h.worker) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.worker[dice.Roll(len(h.worker))]
|
||||||
|
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
|
||||||
|
return w.Proxy(), w.Port(), int(expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Tag() string {
|
||||||
|
return h.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReceiverSettings implements inbound.Handler.
|
||||||
|
func (h *DynamicInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
||||||
|
return serial.ToTypedMessage(h.receiverConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxySettings implements inbound.Handler.
|
||||||
|
func (h *DynamicInboundHandler) ProxySettings() *serial.TypedMessage {
|
||||||
|
if v, ok := h.proxyConfig.(proto.Message); ok {
|
||||||
|
return serial.ToTypedMessage(v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -178,7 +178,15 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
allocStrategy := receiverSettings.AllocationStrategy
|
||||||
|
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
|
||||||
|
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
||||||
|
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
+5
-25
@@ -72,14 +72,7 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isDomain(ob.Target, p.domain) {
|
if isDomain(ob.Target, p.domain) {
|
||||||
opts := pipe.OptionsFromContext(ctx)
|
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||||
uplinkReader, uplinkWriter := pipe.New(opts...)
|
|
||||||
downlinkReader, downlinkWriter := pipe.New(opts...)
|
|
||||||
|
|
||||||
muxClient, err := mux.NewClientWorker(transport.Link{
|
|
||||||
Reader: uplinkReader,
|
|
||||||
Writer: downlinkWriter,
|
|
||||||
}, mux.ClientStrategy{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
@@ -91,24 +84,11 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
|
|
||||||
p.picker.AddWorker(worker)
|
p.picker.AddWorker(worker)
|
||||||
|
|
||||||
inboundLink := &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}
|
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
||||||
requestDone := func() error {
|
select {
|
||||||
if err := buf.Copy(link.Reader, inboundLink.Writer); err != nil {
|
case <-ctx.Done():
|
||||||
return errors.New("failed to transfer request").Base(err)
|
case <-muxClient.WaitClosed():
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
responseDone := func() error {
|
|
||||||
if err := buf.Copy(inboundLink.Reader, link.Writer); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
requestDonePost := task.OnSuccess(requestDone, task.Close(inboundLink.Writer))
|
|
||||||
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
|
|
||||||
common.Interrupt(inboundLink.Reader)
|
|
||||||
common.Interrupt(inboundLink.Writer)
|
|
||||||
return errors.New("connection ends").Base(err)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ func (c routingContext) GetSkipDNSResolve() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c routingContext) GetError() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AsRoutingContext converts a protobuf RoutingContext into an implementation of routing.Context.
|
// AsRoutingContext converts a protobuf RoutingContext into an implementation of routing.Context.
|
||||||
func AsRoutingContext(r *RoutingContext) routing.Context {
|
func AsRoutingContext(r *RoutingContext) routing.Context {
|
||||||
return routingContext{r}
|
return routingContext{r}
|
||||||
|
|||||||
@@ -195,6 +195,9 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
|
|||||||
if rule.Apply(ctx) {
|
if rule.Apply(ctx) {
|
||||||
return rule, ctx, nil
|
return rule, ctx, nil
|
||||||
}
|
}
|
||||||
|
if err := ctx.GetError(); err != nil {
|
||||||
|
return nil, ctx, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
|
if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
|
||||||
@@ -208,6 +211,9 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
|
|||||||
if rule.Apply(ctx) {
|
if rule.Apply(ctx) {
|
||||||
return rule, ctx, nil
|
return rule, ctx, nil
|
||||||
}
|
}
|
||||||
|
if err := ctx.GetError(); err != nil {
|
||||||
|
return nil, ctx, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ctx, common.ErrNoClue
|
return nil, ctx, common.ErrNoClue
|
||||||
|
|||||||
+6
-37
@@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/dispatcher"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -12,11 +13,8 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
//"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
//"github.com/xtls/xray-core/features/policy"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
@@ -66,43 +64,14 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
|
|||||||
if dest.Address != muxCoolAddress {
|
if dest.Address != muxCoolAddress {
|
||||||
return s.dispatcher.DispatchLink(ctx, dest, link)
|
return s.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
}
|
||||||
|
link = s.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
||||||
// For Mux, we need to use pipe to guard against multiple sub-connections writing back responses at the same time
|
worker, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||||
// sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
|
||||||
// ctx, cancel := context.WithCancel(ctx)
|
|
||||||
// timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
|
||||||
// ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
|
|
||||||
opts := pipe.OptionsFromContext(ctx)
|
|
||||||
uplinkReader, uplinkWriter := pipe.New(opts...)
|
|
||||||
downlinkReader, downlinkWriter := pipe.New(opts...)
|
|
||||||
|
|
||||||
_, err := NewServerWorker(ctx, s.dispatcher, &transport.Link{
|
|
||||||
Reader: uplinkReader,
|
|
||||||
Writer: downlinkWriter,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inboundLink := &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}
|
select {
|
||||||
requestDone := func() error {
|
case <-ctx.Done():
|
||||||
//defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
case <-worker.done.Wait():
|
||||||
if err := buf.Copy(link.Reader, inboundLink.Writer); err != nil {
|
|
||||||
return errors.New("failed to transfer request").Base(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
responseDone := func() error {
|
|
||||||
//defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
|
||||||
if err := buf.Copy(inboundLink.Reader, link.Writer); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
requestDonePost := task.OnSuccess(requestDone, task.Close(inboundLink.Writer))
|
|
||||||
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
|
|
||||||
common.Interrupt(inboundLink.Reader)
|
|
||||||
common.Interrupt(inboundLink.Writer)
|
|
||||||
return errors.New("connection ends").Base(err)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/bitmask"
|
"github.com/xtls/xray-core/common/bitmask"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"golang.org/x/sys/cpu"
|
"golang.org/x/sys/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,6 +71,14 @@ type ResponseHeader struct {
|
|||||||
Command ResponseCommand
|
Command ResponseCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommandSwitchAccount struct {
|
||||||
|
Host net.Address
|
||||||
|
Port net.Port
|
||||||
|
ID uuid.UUID
|
||||||
|
Level uint32
|
||||||
|
ValidMin byte
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Keep in sync with crypto/tls/cipher_suites.go.
|
// Keep in sync with crypto/tls/cipher_suites.go.
|
||||||
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
|
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerList struct {
|
||||||
|
sync.RWMutex
|
||||||
|
servers []*ServerSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerList() *ServerList {
|
||||||
|
return &ServerList{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sl *ServerList) AddServer(server *ServerSpec) {
|
||||||
|
sl.Lock()
|
||||||
|
defer sl.Unlock()
|
||||||
|
|
||||||
|
sl.servers = append(sl.servers, server)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sl *ServerList) Size() uint32 {
|
||||||
|
sl.RLock()
|
||||||
|
defer sl.RUnlock()
|
||||||
|
|
||||||
|
return uint32(len(sl.servers))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sl *ServerList) GetServer(idx uint32) *ServerSpec {
|
||||||
|
sl.Lock()
|
||||||
|
defer sl.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if idx >= uint32(len(sl.servers)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
server := sl.servers[idx]
|
||||||
|
if !server.IsValid() {
|
||||||
|
sl.removeServer(idx)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sl *ServerList) removeServer(idx uint32) {
|
||||||
|
n := len(sl.servers)
|
||||||
|
sl.servers[idx] = sl.servers[n-1]
|
||||||
|
sl.servers = sl.servers[:n-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerPicker interface {
|
||||||
|
PickServer() *ServerSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoundRobinServerPicker struct {
|
||||||
|
sync.Mutex
|
||||||
|
serverlist *ServerList
|
||||||
|
nextIndex uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker {
|
||||||
|
return &RoundRobinServerPicker{
|
||||||
|
serverlist: serverlist,
|
||||||
|
nextIndex: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *RoundRobinServerPicker) PickServer() *ServerSpec {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
next := p.nextIndex
|
||||||
|
server := p.serverlist.GetServer(next)
|
||||||
|
if server == nil {
|
||||||
|
next = 0
|
||||||
|
server = p.serverlist.GetServer(0)
|
||||||
|
}
|
||||||
|
next++
|
||||||
|
if next >= p.serverlist.Size() {
|
||||||
|
next = 0
|
||||||
|
}
|
||||||
|
p.nextIndex = next
|
||||||
|
|
||||||
|
return server
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package protocol_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
. "github.com/xtls/xray-core/common/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServerList(t *testing.T) {
|
||||||
|
list := NewServerList()
|
||||||
|
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
|
||||||
|
if list.Size() != 1 {
|
||||||
|
t.Error("list size: ", list.Size())
|
||||||
|
}
|
||||||
|
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||||
|
if list.Size() != 2 {
|
||||||
|
t.Error("list.size: ", list.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
server := list.GetServer(1)
|
||||||
|
if server.Destination().Port != 2 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
server = list.GetServer(1)
|
||||||
|
if server != nil {
|
||||||
|
t.Error("server: ", server)
|
||||||
|
}
|
||||||
|
|
||||||
|
server = list.GetServer(0)
|
||||||
|
if server.Destination().Port != 1 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerPicker(t *testing.T) {
|
||||||
|
list := NewServerList()
|
||||||
|
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
|
||||||
|
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||||
|
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
|
||||||
|
|
||||||
|
picker := NewRoundRobinServerPicker(list)
|
||||||
|
server := picker.PickServer()
|
||||||
|
if server.Destination().Port != 1 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
server = picker.PickServer()
|
||||||
|
if server.Destination().Port != 2 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
server = picker.PickServer()
|
||||||
|
if server.Destination().Port != 3 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
server = picker.PickServer()
|
||||||
|
if server.Destination().Port != 1 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
server = picker.PickServer()
|
||||||
|
if server.Destination().Port != 1 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
server = picker.PickServer()
|
||||||
|
if server.Destination().Port != 1 {
|
||||||
|
t.Error("server: ", server.Destination())
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
-11
@@ -1,30 +1,122 @@
|
|||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerSpec struct {
|
type ValidationStrategy interface {
|
||||||
Destination net.Destination
|
IsValid() bool
|
||||||
User *MemoryUser
|
Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerSpec(dest net.Destination, user *MemoryUser) *ServerSpec {
|
type alwaysValidStrategy struct{}
|
||||||
|
|
||||||
|
func AlwaysValid() ValidationStrategy {
|
||||||
|
return alwaysValidStrategy{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (alwaysValidStrategy) IsValid() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (alwaysValidStrategy) Invalidate() {}
|
||||||
|
|
||||||
|
type timeoutValidStrategy struct {
|
||||||
|
until time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func BeforeTime(t time.Time) ValidationStrategy {
|
||||||
|
return &timeoutValidStrategy{
|
||||||
|
until: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *timeoutValidStrategy) IsValid() bool {
|
||||||
|
return s.until.After(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *timeoutValidStrategy) Invalidate() {
|
||||||
|
s.until = time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerSpec struct {
|
||||||
|
sync.RWMutex
|
||||||
|
dest net.Destination
|
||||||
|
users []*MemoryUser
|
||||||
|
valid ValidationStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerSpec(dest net.Destination, valid ValidationStrategy, users ...*MemoryUser) *ServerSpec {
|
||||||
return &ServerSpec{
|
return &ServerSpec{
|
||||||
Destination: dest,
|
dest: dest,
|
||||||
User: user,
|
users: users,
|
||||||
|
valid: valid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) {
|
func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) {
|
||||||
dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port))
|
dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port))
|
||||||
var dUser *MemoryUser
|
mUsers := make([]*MemoryUser, len(spec.User))
|
||||||
if spec.User != nil {
|
for idx, u := range spec.User {
|
||||||
user, err := spec.User.ToMemoryUser()
|
mUser, err := u.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dUser = user
|
mUsers[idx] = mUser
|
||||||
}
|
}
|
||||||
return NewServerSpec(dest, dUser), nil
|
return NewServerSpec(dest, AlwaysValid(), mUsers...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) Destination() net.Destination {
|
||||||
|
return s.dest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) HasUser(user *MemoryUser) bool {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
for _, u := range s.users {
|
||||||
|
if u.Account.Equals(user.Account) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) AddUser(user *MemoryUser) {
|
||||||
|
if s.HasUser(user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
s.users = append(s.users, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) PickUser() *MemoryUser {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
userCount := len(s.users)
|
||||||
|
switch userCount {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case 1:
|
||||||
|
return s.users[0]
|
||||||
|
default:
|
||||||
|
return s.users[dice.Roll(userCount)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) IsValid() bool {
|
||||||
|
return s.valid.IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerSpec) Invalidate() {
|
||||||
|
s.valid.Invalidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ type ServerEndpoint struct {
|
|||||||
|
|
||||||
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||||
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
|
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
|
||||||
User *User `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"`
|
User []*User `protobuf:"bytes,3,rep,name=user,proto3" json:"user,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ServerEndpoint) Reset() {
|
func (x *ServerEndpoint) Reset() {
|
||||||
@@ -75,7 +75,7 @@ func (x *ServerEndpoint) GetPort() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ServerEndpoint) GetUser() *User {
|
func (x *ServerEndpoint) GetUser() []*User {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.User
|
return x.User
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ var file_common_protocol_server_spec_proto_rawDesc = []byte{
|
|||||||
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72,
|
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72,
|
||||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a,
|
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a,
|
||||||
0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
|
0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||||
0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, 0x5e, 0x0a,
|
0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, 0x5e, 0x0a,
|
||||||
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ import "common/protocol/user.proto";
|
|||||||
message ServerEndpoint {
|
message ServerEndpoint {
|
||||||
xray.common.net.IPOrDomain address = 1;
|
xray.common.net.IPOrDomain address = 1;
|
||||||
uint32 port = 2;
|
uint32 port = 2;
|
||||||
xray.common.protocol.User user = 3;
|
repeated xray.common.protocol.User user = 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package protocol_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
. "github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
|
"github.com/xtls/xray-core/proxy/vmess"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAlwaysValidStrategy(t *testing.T) {
|
||||||
|
strategy := AlwaysValid()
|
||||||
|
if !strategy.IsValid() {
|
||||||
|
t.Error("strategy not valid")
|
||||||
|
}
|
||||||
|
strategy.Invalidate()
|
||||||
|
if !strategy.IsValid() {
|
||||||
|
t.Error("strategy not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeoutValidStrategy(t *testing.T) {
|
||||||
|
strategy := BeforeTime(time.Now().Add(2 * time.Second))
|
||||||
|
if !strategy.IsValid() {
|
||||||
|
t.Error("strategy not valid")
|
||||||
|
}
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
if strategy.IsValid() {
|
||||||
|
t.Error("strategy is valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
strategy = BeforeTime(time.Now().Add(2 * time.Second))
|
||||||
|
strategy.Invalidate()
|
||||||
|
if strategy.IsValid() {
|
||||||
|
t.Error("strategy is valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserInServerSpec(t *testing.T) {
|
||||||
|
uuid1 := uuid.New()
|
||||||
|
uuid2 := uuid.New()
|
||||||
|
|
||||||
|
toAccount := func(a *vmess.Account) Account {
|
||||||
|
account, err := a.AsAccount()
|
||||||
|
common.Must(err)
|
||||||
|
return account
|
||||||
|
}
|
||||||
|
|
||||||
|
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{
|
||||||
|
Email: "test1@example.com",
|
||||||
|
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
|
||||||
|
})
|
||||||
|
if spec.HasUser(&MemoryUser{
|
||||||
|
Email: "test1@example.com",
|
||||||
|
Account: toAccount(&vmess.Account{Id: uuid2.String()}),
|
||||||
|
}) {
|
||||||
|
t.Error("has user: ", uuid2)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.AddUser(&MemoryUser{Email: "test2@example.com"})
|
||||||
|
if !spec.HasUser(&MemoryUser{
|
||||||
|
Email: "test1@example.com",
|
||||||
|
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
|
||||||
|
}) {
|
||||||
|
t.Error("not having user: ", uuid1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPickUser(t *testing.T) {
|
||||||
|
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{Email: "test1@example.com"}, &MemoryUser{Email: "test2@example.com"}, &MemoryUser{Email: "test3@example.com"})
|
||||||
|
user := spec.PickUser()
|
||||||
|
if !strings.HasSuffix(user.Email, "@example.com") {
|
||||||
|
t.Error("user: ", user.Email)
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-7
@@ -63,13 +63,17 @@ func TestXrayClose(t *testing.T) {
|
|||||||
Outbound: []*OutboundHandlerConfig{
|
Outbound: []*OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(0),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(0),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/features"
|
"github.com/xtls/xray-core/features"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,9 @@ type Handler interface {
|
|||||||
ReceiverSettings() *serial.TypedMessage
|
ReceiverSettings() *serial.TypedMessage
|
||||||
// Returns the active proxy settings.
|
// Returns the active proxy settings.
|
||||||
ProxySettings() *serial.TypedMessage
|
ProxySettings() *serial.TypedMessage
|
||||||
|
|
||||||
|
// Deprecated: Do not use in new code.
|
||||||
|
GetRandomInboundProxy() (interface{}, net.Port, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager is a feature that manages InboundHandlers.
|
// Manager is a feature that manages InboundHandlers.
|
||||||
|
|||||||
@@ -49,4 +49,7 @@ type Context interface {
|
|||||||
|
|
||||||
// GetSkipDNSResolve returns a flag switch for weather skip dns resolve during route pick.
|
// GetSkipDNSResolve returns a flag switch for weather skip dns resolve during route pick.
|
||||||
GetSkipDNSResolve() bool
|
GetSkipDNSResolve() bool
|
||||||
|
|
||||||
|
// GetError returns errors during route pick, e.g., built-in-dns fail to resolve domain to IP
|
||||||
|
GetError() error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
@@ -14,6 +12,7 @@ type ResolvableContext struct {
|
|||||||
routing.Context
|
routing.Context
|
||||||
dnsClient dns.Client
|
dnsClient dns.Client
|
||||||
resolvedIPs []net.IP
|
resolvedIPs []net.IP
|
||||||
|
lookupError error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTargetIPs overrides original routing.Context's implementation.
|
// GetTargetIPs overrides original routing.Context's implementation.
|
||||||
@@ -22,6 +21,10 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
|||||||
return ctx.resolvedIPs
|
return ctx.resolvedIPs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|
||||||
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
|
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
|
||||||
ips, _, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
ips, _, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
@@ -32,16 +35,17 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
|||||||
ctx.resolvedIPs = ips
|
ctx.resolvedIPs = ips
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
errors.LogInfoInner(context.Background(), err, "resolve ip for ", domain)
|
ctx.lookupError = errors.New("resolve ip for ", domain).Base(err)
|
||||||
}
|
|
||||||
|
|
||||||
if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
|
|
||||||
return ips
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetError override original routing.Context's implementation.
|
||||||
|
func (ctx *ResolvableContext) GetError() error {
|
||||||
|
return ctx.lookupError
|
||||||
|
}
|
||||||
|
|
||||||
// ContextWithDNSClient creates a new routing context with domain resolving capability.
|
// ContextWithDNSClient creates a new routing context with domain resolving capability.
|
||||||
// Resolved domain IPs can be retrieved by GetTargetIPs().
|
// Resolved domain IPs can be retrieved by GetTargetIPs().
|
||||||
func ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {
|
func ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ func (ctx *Context) GetSkipDNSResolve() bool {
|
|||||||
return ctx.Content.SkipDNSResolve
|
return ctx.Content.SkipDNSResolve
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetError implements routing.Context.
|
||||||
|
func (ctx *Context) GetError() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AsRoutingContext creates a context from context.context with session info.
|
// AsRoutingContext creates a context from context.context with session info.
|
||||||
func AsRoutingContext(ctx context.Context) routing.Context {
|
func AsRoutingContext(ctx context.Context) routing.Context {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
|
|||||||
+5
-14
@@ -68,19 +68,12 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
{
|
{
|
||||||
Address: v.Address,
|
Address: v.Address,
|
||||||
Port: v.Port,
|
Port: v.Port,
|
||||||
|
Users: []json.RawMessage{{}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(v.Username) > 0 {
|
|
||||||
v.Servers[0].Users = []json.RawMessage{{}}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(v.Servers) != 1 {
|
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
|
||||||
return nil, errors.New(`HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead`)
|
for idx, serverConfig := range v.Servers {
|
||||||
}
|
|
||||||
for _, serverConfig := range v.Servers {
|
|
||||||
if len(serverConfig.Users) > 1 {
|
|
||||||
return nil, errors.New(`HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead`)
|
|
||||||
}
|
|
||||||
server := &protocol.ServerEndpoint{
|
server := &protocol.ServerEndpoint{
|
||||||
Address: serverConfig.Address.Build(),
|
Address: serverConfig.Address.Build(),
|
||||||
Port: uint32(serverConfig.Port),
|
Port: uint32(serverConfig.Port),
|
||||||
@@ -105,11 +98,9 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
server.User = user
|
server.User = append(server.User, user)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
config.Server = server
|
config.Server[idx] = server
|
||||||
break
|
|
||||||
}
|
}
|
||||||
config.Header = make([]*http.Header, 0, 32)
|
config.Header = make([]*http.Header, 0, 32)
|
||||||
for key, value := range v.Headers {
|
for key, value := range v.Headers {
|
||||||
|
|||||||
+23
-19
@@ -172,16 +172,16 @@ type ShadowsocksServerTarget struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ShadowsocksClientConfig struct {
|
type ShadowsocksClientConfig struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
Level byte `json:"level"`
|
Level byte `json:"level"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Cipher string `json:"method"`
|
Cipher string `json:"method"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
IVCheck bool `json:"ivCheck"`
|
IVCheck bool `json:"ivCheck"`
|
||||||
UoT bool `json:"uot"`
|
UoT bool `json:"uot"`
|
||||||
UoTVersion int `json:"uotVersion"`
|
UoTVersion int `json:"uotVersion"`
|
||||||
Servers []*ShadowsocksServerTarget `json:"servers"`
|
Servers []*ShadowsocksServerTarget `json:"servers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||||
@@ -200,8 +200,8 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(v.Servers) != 1 {
|
if len(v.Servers) == 0 {
|
||||||
return nil, errors.New(`Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead`)
|
return nil, errors.New("0 Shadowsocks server configured.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(v.Servers) == 1 {
|
if len(v.Servers) == 1 {
|
||||||
@@ -229,7 +229,8 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config := new(shadowsocks.ClientConfig)
|
config := new(shadowsocks.ClientConfig)
|
||||||
for _, server := range v.Servers {
|
serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))
|
||||||
|
for idx, server := range v.Servers {
|
||||||
if C.Contains(shadowaead_2022.List, server.Cipher) {
|
if C.Contains(shadowaead_2022.List, server.Cipher) {
|
||||||
return nil, errors.New("Shadowsocks 2022 accept no multi servers")
|
return nil, errors.New("Shadowsocks 2022 accept no multi servers")
|
||||||
}
|
}
|
||||||
@@ -255,16 +256,19 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
|||||||
ss := &protocol.ServerEndpoint{
|
ss := &protocol.ServerEndpoint{
|
||||||
Address: server.Address.Build(),
|
Address: server.Address.Build(),
|
||||||
Port: uint32(server.Port),
|
Port: uint32(server.Port),
|
||||||
User: &protocol.User{
|
User: []*protocol.User{
|
||||||
Level: uint32(server.Level),
|
{
|
||||||
Email: server.Email,
|
Level: uint32(server.Level),
|
||||||
Account: serial.ToTypedMessage(account),
|
Email: server.Email,
|
||||||
|
Account: serial.ToTypedMessage(account),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Server = ss
|
serverSpecs[idx] = ss
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.Server = serverSpecs
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-14
@@ -86,19 +86,12 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
{
|
{
|
||||||
Address: v.Address,
|
Address: v.Address,
|
||||||
Port: v.Port,
|
Port: v.Port,
|
||||||
|
Users: []json.RawMessage{{}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(v.Username) > 0 {
|
|
||||||
v.Servers[0].Users = []json.RawMessage{{}}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(v.Servers) != 1 {
|
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
|
||||||
return nil, errors.New(`SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead`)
|
for idx, serverConfig := range v.Servers {
|
||||||
}
|
|
||||||
for _, serverConfig := range v.Servers {
|
|
||||||
if len(serverConfig.Users) > 1 {
|
|
||||||
return nil, errors.New(`SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS outbounds and routing balancer instead`)
|
|
||||||
}
|
|
||||||
server := &protocol.ServerEndpoint{
|
server := &protocol.ServerEndpoint{
|
||||||
Address: serverConfig.Address.Build(),
|
Address: serverConfig.Address.Build(),
|
||||||
Port: uint32(serverConfig.Port),
|
Port: uint32(serverConfig.Port),
|
||||||
@@ -123,11 +116,9 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
server.User = user
|
server.User = append(server.User, user)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
config.Server = server
|
config.Server[idx] = server
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-24
@@ -65,19 +65,23 @@ func TestSocksOutboundConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &socks.ClientConfig{
|
Output: &socks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Address: &net.IPOrDomain{
|
||||||
Ip: []byte{127, 0, 0, 1},
|
Address: &net.IPOrDomain_Ip{
|
||||||
|
Ip: []byte{127, 0, 0, 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Port: 1234,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Email: "test@email.com",
|
||||||
|
Account: serial.ToTypedMessage(&socks.Account{
|
||||||
|
Username: "test user",
|
||||||
|
Password: "test pass",
|
||||||
|
}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Port: 1234,
|
|
||||||
User: &protocol.User{
|
|
||||||
Email: "test@email.com",
|
|
||||||
Account: serial.ToTypedMessage(&socks.Account{
|
|
||||||
Username: "test user",
|
|
||||||
Password: "test pass",
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -92,19 +96,23 @@ func TestSocksOutboundConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &socks.ClientConfig{
|
Output: &socks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Address: &net.IPOrDomain{
|
||||||
Ip: []byte{127, 0, 0, 1},
|
Address: &net.IPOrDomain_Ip{
|
||||||
|
Ip: []byte{127, 0, 0, 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Port: 1234,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Email: "test@email.com",
|
||||||
|
Account: serial.ToTypedMessage(&socks.Account{
|
||||||
|
Username: "test user",
|
||||||
|
Password: "test pass",
|
||||||
|
}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Port: 1234,
|
|
||||||
User: &protocol.User{
|
|
||||||
Email: "test@email.com",
|
|
||||||
Account: serial.ToTypedMessage(&socks.Account{
|
|
||||||
Username: "test user",
|
|
||||||
Password: "test pass",
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+22
-20
@@ -28,13 +28,13 @@ type TrojanServerTarget struct {
|
|||||||
|
|
||||||
// TrojanClientConfig is configuration of trojan servers
|
// TrojanClientConfig is configuration of trojan servers
|
||||||
type TrojanClientConfig struct {
|
type TrojanClientConfig struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
Level byte `json:"level"`
|
Level byte `json:"level"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Flow string `json:"flow"`
|
Flow string `json:"flow"`
|
||||||
Servers []*TrojanServerTarget `json:"servers"`
|
Servers []*TrojanServerTarget `json:"servers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
@@ -51,13 +51,15 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(c.Servers) != 1 {
|
if len(c.Servers) == 0 {
|
||||||
return nil, errors.New(`Trojan settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Trojan outbounds and routing balancer instead`)
|
return nil, errors.New("0 Trojan server configured.")
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &trojan.ClientConfig{}
|
config := &trojan.ClientConfig{
|
||||||
|
Server: make([]*protocol.ServerEndpoint, len(c.Servers)),
|
||||||
|
}
|
||||||
|
|
||||||
for _, rec := range c.Servers {
|
for idx, rec := range c.Servers {
|
||||||
if rec.Address == nil {
|
if rec.Address == nil {
|
||||||
return nil, errors.New("Trojan server address is not set.")
|
return nil, errors.New("Trojan server address is not set.")
|
||||||
}
|
}
|
||||||
@@ -71,19 +73,19 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
|||||||
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
|
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Server = &protocol.ServerEndpoint{
|
config.Server[idx] = &protocol.ServerEndpoint{
|
||||||
Address: rec.Address.Build(),
|
Address: rec.Address.Build(),
|
||||||
Port: uint32(rec.Port),
|
Port: uint32(rec.Port),
|
||||||
User: &protocol.User{
|
User: []*protocol.User{
|
||||||
Level: uint32(rec.Level),
|
{
|
||||||
Email: rec.Email,
|
Level: uint32(rec.Level),
|
||||||
Account: serial.ToTypedMessage(&trojan.Account{
|
Email: rec.Email,
|
||||||
Password: rec.Password,
|
Account: serial.ToTypedMessage(&trojan.Account{
|
||||||
}),
|
Password: rec.Password,
|
||||||
|
}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|||||||
+8
-8
@@ -228,20 +228,22 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(c.Vnext) != 1 {
|
if len(c.Vnext) != 1 {
|
||||||
return nil, errors.New(`VLESS settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VLESS outbounds and routing balancer instead`)
|
return nil, errors.New(`VLESS settings: "vnext" should have one and only one member`)
|
||||||
}
|
}
|
||||||
for _, rec := range c.Vnext {
|
config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext))
|
||||||
|
for idx, rec := range c.Vnext {
|
||||||
if rec.Address == nil {
|
if rec.Address == nil {
|
||||||
return nil, errors.New(`VLESS vnext: "address" is not set`)
|
return nil, errors.New(`VLESS vnext: "address" is not set`)
|
||||||
}
|
}
|
||||||
if len(rec.Users) != 1 {
|
if len(rec.Users) != 1 {
|
||||||
return nil, errors.New(`VLESS vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VLESS outbounds and routing balancer instead`)
|
return nil, errors.New(`VLESS vnext: "users" should have one and only one member`)
|
||||||
}
|
}
|
||||||
spec := &protocol.ServerEndpoint{
|
spec := &protocol.ServerEndpoint{
|
||||||
Address: rec.Address.Build(),
|
Address: rec.Address.Build(),
|
||||||
Port: uint32(rec.Port),
|
Port: uint32(rec.Port),
|
||||||
|
User: make([]*protocol.User, len(rec.Users)),
|
||||||
}
|
}
|
||||||
for _, rawUser := range rec.Users {
|
for idx, rawUser := range rec.Users {
|
||||||
user := new(protocol.User)
|
user := new(protocol.User)
|
||||||
if c.Address != nil {
|
if c.Address != nil {
|
||||||
user.Level = c.Level
|
user.Level = c.Level
|
||||||
@@ -325,11 +327,9 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.Account = serial.ToTypedMessage(account)
|
user.Account = serial.ToTypedMessage(account)
|
||||||
spec.User = user
|
spec.User[idx] = user
|
||||||
break
|
|
||||||
}
|
}
|
||||||
config.Vnext = spec
|
config.Vnext[idx] = spec
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|||||||
+34
-26
@@ -35,20 +35,24 @@ func TestVLessOutbound(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &outbound.Config{
|
Output: &outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Domain{
|
Address: &net.IPOrDomain{
|
||||||
Domain: "example.com",
|
Address: &net.IPOrDomain_Domain{
|
||||||
|
Domain: "example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Port: 443,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
|
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
||||||
|
Flow: "xtls-rprx-vision-udp443",
|
||||||
|
Encryption: "none",
|
||||||
|
}),
|
||||||
|
Level: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Port: 443,
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
|
||||||
Flow: "xtls-rprx-vision-udp443",
|
|
||||||
Encryption: "none",
|
|
||||||
}),
|
|
||||||
Level: 0,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -64,20 +68,24 @@ func TestVLessOutbound(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &outbound.Config{
|
Output: &outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Domain{
|
Address: &net.IPOrDomain{
|
||||||
Domain: "example.com",
|
Address: &net.IPOrDomain_Domain{
|
||||||
|
Domain: "example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Port: 443,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
|
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
||||||
|
Flow: "xtls-rprx-vision-udp443",
|
||||||
|
Encryption: "none",
|
||||||
|
}),
|
||||||
|
Level: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Port: 443,
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
|
||||||
Flow: "xtls-rprx-vision-udp443",
|
|
||||||
Encryption: "none",
|
|
||||||
}),
|
|
||||||
Level: 0,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+26
-10
@@ -46,6 +46,17 @@ func (a *VMessAccount) Build() *vmess.Account {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VMessDetourConfig struct {
|
||||||
|
ToTag string `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build implements Buildable
|
||||||
|
func (c *VMessDetourConfig) Build() *inbound.DetourConfig {
|
||||||
|
return &inbound.DetourConfig{
|
||||||
|
To: c.ToTag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type VMessDefaultConfig struct {
|
type VMessDefaultConfig struct {
|
||||||
Level byte `json:"level"`
|
Level byte `json:"level"`
|
||||||
}
|
}
|
||||||
@@ -60,6 +71,7 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
|
|||||||
type VMessInboundConfig struct {
|
type VMessInboundConfig struct {
|
||||||
Users []json.RawMessage `json:"clients"`
|
Users []json.RawMessage `json:"clients"`
|
||||||
Defaults *VMessDefaultConfig `json:"default"`
|
Defaults *VMessDefaultConfig `json:"default"`
|
||||||
|
DetourConfig *VMessDetourConfig `json:"detour"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
@@ -70,6 +82,10 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
|
|||||||
config.Default = c.Defaults.Build()
|
config.Default = c.Defaults.Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.DetourConfig != nil {
|
||||||
|
config.Detour = c.DetourConfig.Build()
|
||||||
|
}
|
||||||
|
|
||||||
config.User = make([]*protocol.User, len(c.Users))
|
config.User = make([]*protocol.User, len(c.Users))
|
||||||
for idx, rawData := range c.Users {
|
for idx, rawData := range c.Users {
|
||||||
user := new(protocol.User)
|
user := new(protocol.User)
|
||||||
@@ -123,15 +139,16 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(c.Receivers) != 1 {
|
if len(c.Receivers) == 0 {
|
||||||
return nil, errors.New(`VMess settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VMess outbounds and routing balancer instead`)
|
return nil, errors.New("0 VMess receiver configured")
|
||||||
}
|
}
|
||||||
for _, rec := range c.Receivers {
|
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers))
|
||||||
if len(rec.Users) != 1 {
|
for idx, rec := range c.Receivers {
|
||||||
return nil, errors.New(`VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead`)
|
if len(rec.Users) == 0 {
|
||||||
|
return nil, errors.New("0 user configured for VMess outbound")
|
||||||
}
|
}
|
||||||
if rec.Address == nil {
|
if rec.Address == nil {
|
||||||
return nil, errors.New(`VMess vnext: "address" is not set`)
|
return nil, errors.New("address is not set in VMess outbound config")
|
||||||
}
|
}
|
||||||
spec := &protocol.ServerEndpoint{
|
spec := &protocol.ServerEndpoint{
|
||||||
Address: rec.Address.Build(),
|
Address: rec.Address.Build(),
|
||||||
@@ -165,11 +182,10 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
account.ID = u.String()
|
account.ID = u.String()
|
||||||
|
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
spec.User = user
|
spec.User = append(spec.User, user)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
config.Receiver = spec
|
serverSpecs[idx] = spec
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
config.Receiver = serverSpecs
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-31
@@ -34,22 +34,26 @@ func TestVMessOutbound(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &outbound.Config{
|
Output: &outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Address: &net.IPOrDomain{
|
||||||
Ip: []byte{127, 0, 0, 1},
|
Address: &net.IPOrDomain_Ip{
|
||||||
},
|
Ip: []byte{127, 0, 0, 1},
|
||||||
},
|
|
||||||
Port: 80,
|
|
||||||
User: &protocol.User{
|
|
||||||
Email: "love@example.com",
|
|
||||||
Level: 255,
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
|
||||||
Type: protocol.SecurityType_AUTO,
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
|
Port: 80,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Email: "love@example.com",
|
||||||
|
Level: 255,
|
||||||
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AUTO,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -64,22 +68,26 @@ func TestVMessOutbound(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &outbound.Config{
|
Output: &outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: &net.IPOrDomain{
|
{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Address: &net.IPOrDomain{
|
||||||
Ip: []byte{127, 0, 0, 1},
|
Address: &net.IPOrDomain_Ip{
|
||||||
},
|
Ip: []byte{127, 0, 0, 1},
|
||||||
},
|
|
||||||
Port: 80,
|
|
||||||
User: &protocol.User{
|
|
||||||
Email: "love@example.com",
|
|
||||||
Level: 255,
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
|
||||||
Type: protocol.SecurityType_AUTO,
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
|
Port: 80,
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Email: "love@example.com",
|
||||||
|
Level: 255,
|
||||||
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AUTO,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -105,7 +113,11 @@ func TestVMessInbound(t *testing.T) {
|
|||||||
],
|
],
|
||||||
"default": {
|
"default": {
|
||||||
"level": 0
|
"level": 0
|
||||||
}
|
},
|
||||||
|
"detour": {
|
||||||
|
"to": "tag_to_detour"
|
||||||
|
},
|
||||||
|
"disableInsecureEncryption": true
|
||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &inbound.Config{
|
Output: &inbound.Config{
|
||||||
@@ -124,6 +136,9 @@ func TestVMessInbound(t *testing.T) {
|
|||||||
Default: &inbound.DefaultConfig{
|
Default: &inbound.DefaultConfig{
|
||||||
Level: 0,
|
Level: 0,
|
||||||
},
|
},
|
||||||
|
Detour: &inbound.DetourConfig{
|
||||||
|
To: "tag_to_detour",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package conf
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -119,12 +120,47 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InboundDetourAllocationConfig struct {
|
||||||
|
Strategy string `json:"strategy"`
|
||||||
|
Concurrency *uint32 `json:"concurrency"`
|
||||||
|
RefreshMin *uint32 `json:"refresh"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build implements Buildable.
|
||||||
|
func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
|
||||||
|
config := new(proxyman.AllocationStrategy)
|
||||||
|
switch strings.ToLower(c.Strategy) {
|
||||||
|
case "always":
|
||||||
|
config.Type = proxyman.AllocationStrategy_Always
|
||||||
|
case "random":
|
||||||
|
config.Type = proxyman.AllocationStrategy_Random
|
||||||
|
case "external":
|
||||||
|
config.Type = proxyman.AllocationStrategy_External
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown allocation strategy: ", c.Strategy)
|
||||||
|
}
|
||||||
|
if c.Concurrency != nil {
|
||||||
|
config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
|
||||||
|
Value: *c.Concurrency,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.RefreshMin != nil {
|
||||||
|
config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
|
||||||
|
Value: *c.RefreshMin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
type InboundDetourConfig struct {
|
type InboundDetourConfig struct {
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
PortList *PortList `json:"port"`
|
PortList *PortList `json:"port"`
|
||||||
ListenOn *Address `json:"listen"`
|
ListenOn *Address `json:"listen"`
|
||||||
Settings *json.RawMessage `json:"settings"`
|
Settings *json.RawMessage `json:"settings"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
|
Allocation *InboundDetourAllocationConfig `json:"allocate"`
|
||||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||||
SniffingConfig *SniffingConfig `json:"sniffing"`
|
SniffingConfig *SniffingConfig `json:"sniffing"`
|
||||||
}
|
}
|
||||||
@@ -161,6 +197,30 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Allocation != nil {
|
||||||
|
concurrency := -1
|
||||||
|
if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
|
||||||
|
concurrency = int(*c.Allocation.Concurrency)
|
||||||
|
}
|
||||||
|
portRange := 0
|
||||||
|
|
||||||
|
for _, pr := range c.PortList.Range {
|
||||||
|
portRange += int(pr.To - pr.From + 1)
|
||||||
|
}
|
||||||
|
if concurrency >= 0 && concurrency >= portRange {
|
||||||
|
var ports strings.Builder
|
||||||
|
for _, pr := range c.PortList.Range {
|
||||||
|
fmt.Fprintf(&ports, "%d-%d ", pr.From, pr.To)
|
||||||
|
}
|
||||||
|
return nil, errors.New("not enough ports. concurrency = ", concurrency, " ports: ", ports.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
as, err := c.Allocation.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
receiverSettings.AllocationStrategy = as
|
||||||
|
}
|
||||||
if c.StreamSetting != nil {
|
if c.StreamSetting != nil {
|
||||||
ss, err := c.StreamSetting.Build()
|
ss, err := c.StreamSetting.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ func TestXrayConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"protocol": "vmess",
|
"protocol": "vmess",
|
||||||
"port": "443-500",
|
"port": "443-500",
|
||||||
|
"allocate": {
|
||||||
|
"strategy": "random",
|
||||||
|
"concurrency": 3
|
||||||
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"clients": [
|
"clients": [
|
||||||
{
|
{
|
||||||
@@ -119,6 +123,12 @@ func TestXrayConfig(t *testing.T) {
|
|||||||
From: 443,
|
From: 443,
|
||||||
To: 500,
|
To: 500,
|
||||||
}}},
|
}}},
|
||||||
|
AllocationStrategy: &proxyman.AllocationStrategy{
|
||||||
|
Type: proxyman.AllocationStrategy_Random,
|
||||||
|
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
|
||||||
|
Value: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
StreamSettings: &internet.StreamConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
ProtocolName: "websocket",
|
ProtocolName: "websocket",
|
||||||
TransportSettings: []*internet.TransportConfig{
|
TransportSettings: []*internet.TransportConfig{
|
||||||
|
|||||||
+16
-10
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
server *protocol.ServerSpec
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
header []*Header
|
header []*Header
|
||||||
}
|
}
|
||||||
@@ -48,17 +48,21 @@ var (
|
|||||||
|
|
||||||
// NewClient create a new http client based on the given config.
|
// NewClient create a new http client based on the given config.
|
||||||
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
||||||
if config.Server == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no target server found`)
|
for _, rec := range config.Server {
|
||||||
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to get server spec").Base(err)
|
||||||
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Server)
|
if serverList.Size() == 0 {
|
||||||
if err != nil {
|
return nil, errors.New("0 target server")
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
return &Client{
|
return &Client{
|
||||||
server: server,
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
header: config.Header,
|
header: config.Header,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -80,9 +84,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
return errors.New("UDP is not supported by HTTP outbound")
|
return errors.New("UDP is not supported by HTTP outbound")
|
||||||
}
|
}
|
||||||
|
|
||||||
server := c.server
|
var user *protocol.MemoryUser
|
||||||
dest := server.Destination
|
|
||||||
user := server.User
|
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
mbuf, _ := link.Reader.ReadMultiBuffer()
|
mbuf, _ := link.Reader.ReadMultiBuffer()
|
||||||
@@ -100,6 +102,10 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
|
server := c.serverPicker.PickServer()
|
||||||
|
dest := server.Destination()
|
||||||
|
user = server.PickUser()
|
||||||
|
|
||||||
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, header, firstPayload)
|
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, header, firstPayload)
|
||||||
if netConn != nil {
|
if netConn != nil {
|
||||||
if _, ok := netConn.(*http2Conn); !ok {
|
if _, ok := netConn.(*http2Conn); !ok {
|
||||||
|
|||||||
@@ -196,8 +196,8 @@ type ClientConfig struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Sever is a list of HTTP server addresses.
|
// Sever is a list of HTTP server addresses.
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
|
||||||
Header []*Header `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty"`
|
Header []*Header `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
func (x *ClientConfig) Reset() {
|
||||||
@@ -230,7 +230,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_http_config_proto_rawDescGZIP(), []int{3}
|
return file_proxy_http_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
|
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Server
|
return x.Server
|
||||||
}
|
}
|
||||||
@@ -275,7 +275,7 @@ var file_proxy_http_config_proto_rawDesc = []byte{
|
|||||||
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x7d, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43,
|
0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x7d, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72,
|
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72,
|
||||||
0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,
|
0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,
|
||||||
0x76, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20,
|
0x76, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20,
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ message Header {
|
|||||||
// ClientConfig is the protobuf config for HTTP proxy client.
|
// ClientConfig is the protobuf config for HTTP proxy client.
|
||||||
message ClientConfig {
|
message ClientConfig {
|
||||||
// Sever is a list of HTTP server addresses.
|
// Sever is a list of HTTP server addresses.
|
||||||
xray.common.protocol.ServerEndpoint server = 1;
|
repeated xray.common.protocol.ServerEndpoint server = 1;
|
||||||
repeated Header header = 2;
|
repeated Header header = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-12
@@ -22,23 +22,27 @@ import (
|
|||||||
|
|
||||||
// Client is a inbound handler for Shadowsocks protocol
|
// Client is a inbound handler for Shadowsocks protocol
|
||||||
type Client struct {
|
type Client struct {
|
||||||
server *protocol.ServerSpec
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient create a new Shadowsocks client.
|
// NewClient create a new Shadowsocks client.
|
||||||
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
||||||
if config.Server == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no target server found`)
|
for _, rec := range config.Server {
|
||||||
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse server spec").Base(err)
|
||||||
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Server)
|
if serverList.Size() == 0 {
|
||||||
if err != nil {
|
return nil, errors.New("0 server")
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
client := &Client{
|
client := &Client{
|
||||||
server: server,
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
}
|
}
|
||||||
return client, nil
|
return client, nil
|
||||||
@@ -56,12 +60,13 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
destination := ob.Target
|
destination := ob.Target
|
||||||
network := destination.Network
|
network := destination.Network
|
||||||
|
|
||||||
server := c.server
|
var server *protocol.ServerSpec
|
||||||
dest := server.Destination
|
|
||||||
dest.Network = network
|
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
|
server = c.serverPicker.PickServer()
|
||||||
|
dest := server.Destination()
|
||||||
|
dest.Network = network
|
||||||
rawConn, err := dialer.Dial(ctx, dest)
|
rawConn, err := dialer.Dial(ctx, dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -73,7 +78,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination().NetAddr())
|
||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -88,7 +93,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
request.Command = protocol.RequestCommandUDP
|
request.Command = protocol.RequestCommandUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
user := server.User
|
user := server.PickUser()
|
||||||
_, ok := user.Account.(*MemoryAccount)
|
_, ok := user.Account.(*MemoryAccount)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("user account is not valid")
|
return errors.New("user account is not valid")
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ type ClientConfig struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
func (x *ClientConfig) Reset() {
|
||||||
@@ -232,7 +232,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2}
|
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
|
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Server
|
return x.Server
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
|
|||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
|
||||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22,
|
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22,
|
||||||
0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
|
0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64,
|
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64,
|
||||||
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x74, 0x0a,
|
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x74, 0x0a,
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ message ServerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ClientConfig {
|
message ClientConfig {
|
||||||
xray.common.protocol.ServerEndpoint server = 1;
|
repeated xray.common.protocol.ServerEndpoint server = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-10
@@ -22,23 +22,27 @@ import (
|
|||||||
|
|
||||||
// Client is a Socks5 client.
|
// Client is a Socks5 client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
server *protocol.ServerSpec
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient create a new Socks5 client based on the given config.
|
// NewClient create a new Socks5 client based on the given config.
|
||||||
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
||||||
if config.Server == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no target server found`)
|
for _, rec := range config.Server {
|
||||||
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to get server spec").Base(err)
|
||||||
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Server)
|
if serverList.Size() == 0 {
|
||||||
if err != nil {
|
return nil, errors.New("0 target server")
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
c := &Client{
|
c := &Client{
|
||||||
server: server,
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,12 +62,15 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
destination := ob.Target
|
destination := ob.Target
|
||||||
|
|
||||||
// Outbound server.
|
// Outbound server.
|
||||||
server := c.server
|
var server *protocol.ServerSpec
|
||||||
dest := server.Destination
|
// Outbound server's destination.
|
||||||
|
var dest net.Destination
|
||||||
// Connection to the outbound server.
|
// Connection to the outbound server.
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
|
server = c.serverPicker.PickServer()
|
||||||
|
dest = server.Destination()
|
||||||
rawConn, err := dialer.Dial(ctx, dest)
|
rawConn, err := dialer.Dial(ctx, dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -94,7 +101,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
request.Command = protocol.RequestCommandUDP
|
request.Command = protocol.RequestCommandUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
user := server.User
|
user := server.PickUser()
|
||||||
if user != nil {
|
if user != nil {
|
||||||
request.User = user
|
request.User = user
|
||||||
p = c.policyManager.ForLevel(user.Level)
|
p = c.policyManager.ForLevel(user.Level)
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ type ClientConfig struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Sever is a list of Socks server addresses.
|
// Sever is a list of Socks server addresses.
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
func (x *ClientConfig) Reset() {
|
||||||
@@ -243,7 +243,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_socks_config_proto_rawDescGZIP(), []int{2}
|
return file_proxy_socks_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
|
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Server
|
return x.Server
|
||||||
}
|
}
|
||||||
@@ -286,7 +286,7 @@ var file_proxy_socks_config_proto_rawDesc = []byte{
|
|||||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
|
0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01,
|
0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||||
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76,
|
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76,
|
||||||
0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76,
|
0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76,
|
||||||
0x65, 0x72, 0x2a, 0x25, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b,
|
0x65, 0x72, 0x2a, 0x25, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b,
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ message ServerConfig {
|
|||||||
// ClientConfig is the protobuf config for Socks client.
|
// ClientConfig is the protobuf config for Socks client.
|
||||||
message ClientConfig {
|
message ClientConfig {
|
||||||
// Sever is a list of Socks server addresses.
|
// Sever is a list of Socks server addresses.
|
||||||
xray.common.protocol.ServerEndpoint server = 1;
|
repeated xray.common.protocol.ServerEndpoint server = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-11
@@ -22,23 +22,27 @@ import (
|
|||||||
|
|
||||||
// Client is a inbound handler for trojan protocol
|
// Client is a inbound handler for trojan protocol
|
||||||
type Client struct {
|
type Client struct {
|
||||||
server *protocol.ServerSpec
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient create a new trojan client.
|
// NewClient create a new trojan client.
|
||||||
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
||||||
if config.Server == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no target server found`)
|
for _, rec := range config.Server {
|
||||||
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse server spec").Base(err)
|
||||||
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Server)
|
if serverList.Size() == 0 {
|
||||||
if err != nil {
|
return nil, errors.New("0 server")
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
client := &Client{
|
client := &Client{
|
||||||
server: server,
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
}
|
}
|
||||||
return client, nil
|
return client, nil
|
||||||
@@ -56,11 +60,12 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
destination := ob.Target
|
destination := ob.Target
|
||||||
network := destination.Network
|
network := destination.Network
|
||||||
|
|
||||||
server := c.server
|
var server *protocol.ServerSpec
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
rawConn, err := dialer.Dial(ctx, server.Destination)
|
server = c.serverPicker.PickServer()
|
||||||
|
rawConn, err := dialer.Dial(ctx, server.Destination())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -71,11 +76,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination().NetAddr())
|
||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
user := server.User
|
user := server.PickUser()
|
||||||
account, ok := user.Account.(*MemoryAccount)
|
account, ok := user.Account.(*MemoryAccount)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("user account is not valid")
|
return errors.New("user account is not valid")
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ type ClientConfig struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
func (x *ClientConfig) Reset() {
|
||||||
@@ -189,7 +189,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}
|
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
|
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Server
|
return x.Server
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ var file_proxy_trojan_config_proto_rawDesc = []byte{
|
|||||||
0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20,
|
0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20,
|
||||||
0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
|
0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
|
||||||
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72,
|
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72,
|
||||||
0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||||
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
|
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
|
||||||
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,
|
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ message Fallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ClientConfig {
|
message ClientConfig {
|
||||||
xray.common.protocol.ServerEndpoint server = 1;
|
repeated xray.common.protocol.ServerEndpoint server = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ServerConfig {
|
message ServerConfig {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type Config struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Vnext *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=vnext,proto3" json:"vnext,omitempty"`
|
Vnext []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=vnext,proto3" json:"vnext,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -59,7 +59,7 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}
|
return file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetVnext() *protocol.ServerEndpoint {
|
func (x *Config) GetVnext() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Vnext
|
return x.Vnext
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ var file_proxy_vless_outbound_config_proto_rawDesc = []byte{
|
|||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x22, 0x44, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x05, 0x76,
|
0x6f, 0x22, 0x44, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x05, 0x76,
|
||||||
0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
|
0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||||
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||||
0x52, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
0x52, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ option java_multiple_files = true;
|
|||||||
import "common/protocol/server_spec.proto";
|
import "common/protocol/server_spec.proto";
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
xray.common.protocol.ServerEndpoint vnext = 1;
|
repeated xray.common.protocol.ServerEndpoint vnext = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ func init() {
|
|||||||
|
|
||||||
// Handler is an outbound connection handler for VLess protocol.
|
// Handler is an outbound connection handler for VLess protocol.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
server *protocol.ServerSpec
|
serverList *protocol.ServerList
|
||||||
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
cone bool
|
cone bool
|
||||||
encryption *encryption.ClientInstance
|
encryption *encryption.ClientInstance
|
||||||
@@ -56,22 +57,24 @@ type Handler struct {
|
|||||||
|
|
||||||
// New creates a new VLess outbound handler.
|
// New creates a new VLess outbound handler.
|
||||||
func New(ctx context.Context, config *Config) (*Handler, error) {
|
func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||||
if config.Vnext == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no vnext found`)
|
for _, rec := range config.Vnext {
|
||||||
}
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Vnext)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, errors.New("failed to parse server spec").Base(err).AtError()
|
||||||
return nil, errors.New("failed to get server spec").Base(err).AtError()
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
handler := &Handler{
|
handler := &Handler{
|
||||||
server: server,
|
serverList: serverList,
|
||||||
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
cone: ctx.Value("cone").(bool),
|
cone: ctx.Value("cone").(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
a := handler.server.User.Account.(*vless.MemoryAccount)
|
a := handler.serverPicker.PickServer().PickUser().Account.(*vless.MemoryAccount)
|
||||||
if a.Encryption != "" && a.Encryption != "none" {
|
if a.Encryption != "" && a.Encryption != "none" {
|
||||||
s := strings.Split(a.Encryption, ".")
|
s := strings.Split(a.Encryption, ".")
|
||||||
var nfsPKeysBytes [][]byte
|
var nfsPKeysBytes [][]byte
|
||||||
@@ -122,12 +125,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
ob.Name = "vless"
|
ob.Name = "vless"
|
||||||
|
|
||||||
rec := h.server
|
var rec *protocol.ServerSpec
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
if err := retry.ExponentialBackoff(5, 200).On(func() error {
|
if err := retry.ExponentialBackoff(5, 200).On(func() error {
|
||||||
|
rec = h.serverPicker.PickServer()
|
||||||
var err error
|
var err error
|
||||||
conn, err = dialer.Dial(ctx, rec.Destination)
|
conn, err = dialer.Dial(ctx, rec.Destination())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -142,7 +145,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
iConn = statConn.Connection
|
iConn = statConn.Connection
|
||||||
}
|
}
|
||||||
target := ob.Target
|
target := ob.Target
|
||||||
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
|
||||||
|
|
||||||
if h.encryption != nil {
|
if h.encryption != nil {
|
||||||
var err error
|
var err error
|
||||||
@@ -169,7 +172,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
request := &protocol.RequestHeader{
|
request := &protocol.RequestHeader{
|
||||||
Version: encoding.Version,
|
Version: encoding.Version,
|
||||||
User: rec.User,
|
User: rec.PickUser(),
|
||||||
Command: command,
|
Command: command,
|
||||||
Address: target.Address,
|
Address: target.Address,
|
||||||
Port: target.Port,
|
Port: target.Port,
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import (
|
|||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -26,6 +29,9 @@ func MarshalCommand(command interface{}, writer io.Writer) error {
|
|||||||
var cmdID byte
|
var cmdID byte
|
||||||
var factory CommandFactory
|
var factory CommandFactory
|
||||||
switch command.(type) {
|
switch command.(type) {
|
||||||
|
case *protocol.CommandSwitchAccount:
|
||||||
|
factory = new(CommandSwitchAccountFactory)
|
||||||
|
cmdID = 1
|
||||||
default:
|
default:
|
||||||
return ErrUnknownCommand
|
return ErrUnknownCommand
|
||||||
}
|
}
|
||||||
@@ -61,6 +67,8 @@ func UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error)
|
|||||||
|
|
||||||
var factory CommandFactory
|
var factory CommandFactory
|
||||||
switch cmdID {
|
switch cmdID {
|
||||||
|
case 1:
|
||||||
|
factory = new(CommandSwitchAccountFactory)
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnknownCommand
|
return nil, ErrUnknownCommand
|
||||||
}
|
}
|
||||||
@@ -71,3 +79,67 @@ type CommandFactory interface {
|
|||||||
Marshal(command interface{}, writer io.Writer) error
|
Marshal(command interface{}, writer io.Writer) error
|
||||||
Unmarshal(data []byte) (interface{}, error)
|
Unmarshal(data []byte) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommandSwitchAccountFactory struct{}
|
||||||
|
|
||||||
|
func (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {
|
||||||
|
cmd, ok := command.(*protocol.CommandSwitchAccount)
|
||||||
|
if !ok {
|
||||||
|
return ErrCommandTypeMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
hostStr := ""
|
||||||
|
if cmd.Host != nil {
|
||||||
|
hostStr = cmd.Host.String()
|
||||||
|
}
|
||||||
|
common.Must2(writer.Write([]byte{byte(len(hostStr))}))
|
||||||
|
|
||||||
|
if len(hostStr) > 0 {
|
||||||
|
common.Must2(writer.Write([]byte(hostStr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
common.Must2(serial.WriteUint16(writer, cmd.Port.Value()))
|
||||||
|
|
||||||
|
idBytes := cmd.ID.Bytes()
|
||||||
|
common.Must2(writer.Write(idBytes))
|
||||||
|
common.Must2(serial.WriteUint16(writer, 0)) // compatible with legacy alterId
|
||||||
|
common.Must2(writer.Write([]byte{byte(cmd.Level)}))
|
||||||
|
|
||||||
|
common.Must2(writer.Write([]byte{cmd.ValidMin}))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
|
||||||
|
cmd := new(protocol.CommandSwitchAccount)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
lenHost := int(data[0])
|
||||||
|
if len(data) < lenHost+1 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
if lenHost > 0 {
|
||||||
|
cmd.Host = net.ParseAddress(string(data[1 : 1+lenHost]))
|
||||||
|
}
|
||||||
|
portStart := 1 + lenHost
|
||||||
|
if len(data) < portStart+2 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
cmd.Port = net.PortFromBytes(data[portStart : portStart+2])
|
||||||
|
idStart := portStart + 2
|
||||||
|
if len(data) < idStart+16 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
cmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16])
|
||||||
|
levelStart := idStart + 16 + 2
|
||||||
|
if len(data) < levelStart+1 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
cmd.Level = uint32(data[levelStart])
|
||||||
|
timeStart := levelStart + 1
|
||||||
|
if len(data) < timeStart+1 {
|
||||||
|
return nil, ErrInsufficientLength
|
||||||
|
}
|
||||||
|
cmd.ValidMin = data[timeStart]
|
||||||
|
return cmd, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package encoding_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/buf"
|
||||||
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
|
. "github.com/xtls/xray-core/proxy/vmess/encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSwitchAccount(t *testing.T) {
|
||||||
|
sa := &protocol.CommandSwitchAccount{
|
||||||
|
Port: 1234,
|
||||||
|
ID: uuid.New(),
|
||||||
|
Level: 128,
|
||||||
|
ValidMin: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := buf.New()
|
||||||
|
common.Must(MarshalCommand(sa, buffer))
|
||||||
|
|
||||||
|
cmd, err := UnmarshalCommand(1, buffer.BytesFrom(2))
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
sa2, ok := cmd.(*protocol.CommandSwitchAccount)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("failed to convert command to CommandSwitchAccount")
|
||||||
|
}
|
||||||
|
if r := cmp.Diff(sa2, sa); r != "" {
|
||||||
|
t.Error(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSwitchAccountBugOffByOne(t *testing.T) {
|
||||||
|
sa := &protocol.CommandSwitchAccount{
|
||||||
|
Port: 1234,
|
||||||
|
ID: uuid.New(),
|
||||||
|
Level: 128,
|
||||||
|
ValidMin: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := buf.New()
|
||||||
|
csaf := CommandSwitchAccountFactory{}
|
||||||
|
common.Must(csaf.Marshal(sa, buffer))
|
||||||
|
|
||||||
|
Payload := buffer.Bytes()
|
||||||
|
|
||||||
|
cmd, err := csaf.Unmarshal(Payload[:len(Payload)-1])
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, cmd)
|
||||||
|
}
|
||||||
@@ -118,6 +118,7 @@ type Config struct {
|
|||||||
|
|
||||||
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
|
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
|
||||||
Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
|
Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
|
||||||
|
Detour *DetourConfig `protobuf:"bytes,3,opt,name=detour,proto3" json:"detour,omitempty"` // 4 is for legacy setting
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -164,6 +165,13 @@ func (x *Config) GetDefault() *DefaultConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetDetour() *DetourConfig {
|
||||||
|
if x != nil {
|
||||||
|
return x.Detour
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor
|
var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
|
var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
|
||||||
@@ -177,21 +185,26 @@ var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
|
|||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61,
|
||||||
0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76,
|
0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76,
|
||||||
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22,
|
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22,
|
||||||
0x7b, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65,
|
0xbb, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73,
|
||||||
0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55,
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
|
||||||
0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, 0x66,
|
0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65,
|
||||||
0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72,
|
||||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e,
|
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69,
|
||||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e,
|
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f,
|
||||||
0x66, 0x69, 0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x6a, 0x0a, 0x1c,
|
0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a,
|
||||||
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
|
0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e,
|
||||||
0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73,
|
||||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
|
0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x42, 0x6a, 0x0a,
|
||||||
0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18,
|
0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73,
|
0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a,
|
||||||
0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x2d, 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, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||||
|
0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02,
|
||||||
|
0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73,
|
||||||
|
0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -216,11 +229,12 @@ var file_proxy_vmess_inbound_config_proto_goTypes = []any{
|
|||||||
var file_proxy_vmess_inbound_config_proto_depIdxs = []int32{
|
var file_proxy_vmess_inbound_config_proto_depIdxs = []int32{
|
||||||
3, // 0: xray.proxy.vmess.inbound.Config.user:type_name -> xray.common.protocol.User
|
3, // 0: xray.proxy.vmess.inbound.Config.user:type_name -> xray.common.protocol.User
|
||||||
1, // 1: xray.proxy.vmess.inbound.Config.default:type_name -> xray.proxy.vmess.inbound.DefaultConfig
|
1, // 1: xray.proxy.vmess.inbound.Config.default:type_name -> xray.proxy.vmess.inbound.DefaultConfig
|
||||||
2, // [2:2] is the sub-list for method output_type
|
0, // 2: xray.proxy.vmess.inbound.Config.detour:type_name -> xray.proxy.vmess.inbound.DetourConfig
|
||||||
2, // [2:2] is the sub-list for method input_type
|
3, // [3:3] is the sub-list for method output_type
|
||||||
2, // [2:2] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for method input_type
|
||||||
2, // [2:2] is the sub-list for extension extendee
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
0, // [0:2] is the sub-list for field type_name
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
|
0, // [0:3] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_vmess_inbound_config_proto_init() }
|
func init() { file_proxy_vmess_inbound_config_proto_init() }
|
||||||
|
|||||||
@@ -19,4 +19,6 @@ message DefaultConfig {
|
|||||||
message Config {
|
message Config {
|
||||||
repeated xray.common.protocol.User user = 1;
|
repeated xray.common.protocol.User user = 1;
|
||||||
DefaultConfig default = 2;
|
DefaultConfig default = 2;
|
||||||
|
DetourConfig detour = 3;
|
||||||
|
// 4 is for legacy setting
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-19
@@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/signal"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
feature_inbound "github.com/xtls/xray-core/features/inbound"
|
feature_inbound "github.com/xtls/xray-core/features/inbound"
|
||||||
@@ -21,7 +23,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/proxy/vmess"
|
"github.com/xtls/xray-core/proxy/vmess"
|
||||||
"github.com/xtls/xray-core/proxy/vmess/encoding"
|
"github.com/xtls/xray-core/proxy/vmess/encoding"
|
||||||
"github.com/xtls/xray-core/transport"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,6 +106,7 @@ type Handler struct {
|
|||||||
inboundHandlerManager feature_inbound.Manager
|
inboundHandlerManager feature_inbound.Manager
|
||||||
clients *vmess.TimedUserValidator
|
clients *vmess.TimedUserValidator
|
||||||
usersByEmail *userByEmail
|
usersByEmail *userByEmail
|
||||||
|
detours *DetourConfig
|
||||||
sessionHistory *encoding.SessionHistory
|
sessionHistory *encoding.SessionHistory
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +117,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
|
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
|
||||||
clients: vmess.NewTimedUserValidator(),
|
clients: vmess.NewTimedUserValidator(),
|
||||||
|
detours: config.Detour,
|
||||||
usersByEmail: newUserByEmail(config.GetDefaultValue()),
|
usersByEmail: newUserByEmail(config.GetDefaultValue()),
|
||||||
sessionHistory: encoding.NewSessionHistory(),
|
sessionHistory: encoding.NewSessionHistory(),
|
||||||
}
|
}
|
||||||
@@ -183,6 +186,44 @@ func (h *Handler) RemoveUser(ctx context.Context, email string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output *buf.BufferedWriter) error {
|
||||||
|
session.EncodeResponseHeader(response, output)
|
||||||
|
|
||||||
|
bodyWriter, err := session.EncodeResponseBody(request, output)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to start decoding response").Base(err)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Optimize for small response packet
|
||||||
|
data, err := input.ReadMultiBuffer()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bodyWriter.WriteMultiBuffer(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := output.SetBuffered(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
account := request.User.Account.(*vmess.MemoryAccount)
|
||||||
|
|
||||||
|
if request.Option.Has(protocol.RequestOptionChunkStream) && !account.NoTerminationSignal {
|
||||||
|
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Process implements proxy.Inbound.Process().
|
// Process implements proxy.Inbound.Process().
|
||||||
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := h.policyManager.ForLevel(0)
|
sessionPolicy := h.policyManager.ForLevel(0)
|
||||||
@@ -236,33 +277,84 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
inbound.User = request.User
|
inbound.User = request.User
|
||||||
|
|
||||||
bodyReader, err := svrSession.DecodeRequestBody(request, reader)
|
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||||
|
|
||||||
|
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
|
||||||
|
link, err := dispatcher.Dispatch(ctx, request.Destination())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to start decoding").Base(err)
|
return errors.New("failed to dispatch request to ", request.Destination()).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
writer := buf.NewBufferedWriter(buf.NewWriter(connection))
|
requestDone := func() error {
|
||||||
response := &protocol.ResponseHeader{
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
Command: h.generateCommand(ctx, request),
|
|
||||||
}
|
|
||||||
svrSession.EncodeResponseHeader(response, writer)
|
|
||||||
bodyWriter, err := svrSession.EncodeResponseBody(request, writer)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to start decoding response").Base(err)
|
|
||||||
}
|
|
||||||
writer.SetFlushNext()
|
|
||||||
|
|
||||||
if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{
|
bodyReader, err := svrSession.DecodeRequestBody(request, reader)
|
||||||
Reader: bodyReader,
|
if err != nil {
|
||||||
Writer: bodyWriter},
|
return errors.New("failed to start decoding").Base(err)
|
||||||
); err != nil {
|
}
|
||||||
return errors.New("failed to dispatch request").Base(err)
|
if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
|
||||||
|
return errors.New("failed to transfer request").Base(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
responseDone := func() error {
|
||||||
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
|
|
||||||
|
writer := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
response := &protocol.ResponseHeader{
|
||||||
|
Command: h.generateCommand(ctx, request),
|
||||||
|
}
|
||||||
|
return transferResponse(timer, svrSession, request, response, link.Reader, writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestDonePost := task.OnSuccess(requestDone, task.Close(link.Writer))
|
||||||
|
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
|
||||||
|
common.Interrupt(link.Reader)
|
||||||
|
common.Interrupt(link.Writer)
|
||||||
|
return errors.New("connection ends").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stub command generator
|
|
||||||
func (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {
|
func (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {
|
||||||
|
if h.detours != nil {
|
||||||
|
tag := h.detours.To
|
||||||
|
if h.inboundHandlerManager != nil {
|
||||||
|
handler, err := h.inboundHandlerManager.GetHandler(ctx, tag)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogWarningInner(ctx, err, "failed to get detour handler: ", tag)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
|
||||||
|
inboundHandler, ok := proxyHandler.(*Handler)
|
||||||
|
if ok && inboundHandler != nil {
|
||||||
|
if availableMin > 255 {
|
||||||
|
availableMin = 255
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.LogDebug(ctx, "pick detour handler for port ", port, " for ", availableMin, " minutes.")
|
||||||
|
user := inboundHandler.GetOrGenerateUser(request.User.Email)
|
||||||
|
if user == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
account := user.Account.(*vmess.MemoryAccount)
|
||||||
|
return &protocol.CommandSwitchAccount{
|
||||||
|
Port: port,
|
||||||
|
ID: account.ID.UUID(),
|
||||||
|
Level: user.Level,
|
||||||
|
ValidMin: byte(availableMin),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,41 @@
|
|||||||
package outbound
|
package outbound
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/proxy/vmess"
|
||||||
)
|
)
|
||||||
|
|
||||||
// As a stub command consumer.
|
func (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
|
||||||
|
rawAccount := &vmess.Account{
|
||||||
|
Id: cmd.ID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AUTO,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := rawAccount.AsAccount()
|
||||||
|
common.Must(err)
|
||||||
|
user := &protocol.MemoryUser{
|
||||||
|
Email: "",
|
||||||
|
Level: cmd.Level,
|
||||||
|
Account: account,
|
||||||
|
}
|
||||||
|
dest := net.TCPDestination(cmd.Host, cmd.Port)
|
||||||
|
until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)
|
||||||
|
h.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
|
func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
|
||||||
switch cmd.(type) {
|
switch typedCommand := cmd.(type) {
|
||||||
|
case *protocol.CommandSwitchAccount:
|
||||||
|
if typedCommand.Host == nil {
|
||||||
|
typedCommand.Host = dest.Address
|
||||||
|
}
|
||||||
|
h.handleSwitchAccount(typedCommand)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type Config struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Receiver *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=Receiver,proto3" json:"Receiver,omitempty"`
|
Receiver []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=Receiver,proto3" json:"Receiver,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -59,7 +59,7 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0}
|
return file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetReceiver() *protocol.ServerEndpoint {
|
func (x *Config) GetReceiver() []*protocol.ServerEndpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Receiver
|
return x.Receiver
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ var file_proxy_vmess_outbound_config_proto_rawDesc = []byte{
|
|||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a, 0x08, 0x52,
|
0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a, 0x08, 0x52,
|
||||||
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
|
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f,
|
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f,
|
||||||
0x69, 0x6e, 0x74, 0x52, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6d, 0x0a,
|
0x69, 0x6e, 0x74, 0x52, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6d, 0x0a,
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ option java_multiple_files = true;
|
|||||||
import "common/protocol/server_spec.proto";
|
import "common/protocol/server_spec.proto";
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
xray.common.protocol.ServerEndpoint Receiver = 1;
|
repeated xray.common.protocol.ServerEndpoint Receiver = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,24 +29,27 @@ import (
|
|||||||
|
|
||||||
// Handler is an outbound connection handler for VMess protocol.
|
// Handler is an outbound connection handler for VMess protocol.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
server *protocol.ServerSpec
|
serverList *protocol.ServerList
|
||||||
|
serverPicker protocol.ServerPicker
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
cone bool
|
cone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new VMess outbound handler.
|
// New creates a new VMess outbound handler.
|
||||||
func New(ctx context.Context, config *Config) (*Handler, error) {
|
func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||||
if config.Receiver == nil {
|
serverList := protocol.NewServerList()
|
||||||
return nil, errors.New(`no vnext found`)
|
for _, rec := range config.Receiver {
|
||||||
}
|
s, err := protocol.NewServerSpecFromPB(rec)
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Receiver)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, errors.New("failed to parse server spec").Base(err)
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
}
|
||||||
|
serverList.AddServer(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
handler := &Handler{
|
handler := &Handler{
|
||||||
server: server,
|
serverList: serverList,
|
||||||
|
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
cone: ctx.Value("cone").(bool),
|
cone: ctx.Value("cone").(bool),
|
||||||
}
|
}
|
||||||
@@ -64,11 +67,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
ob.Name = "vmess"
|
ob.Name = "vmess"
|
||||||
ob.CanSpliceCopy = 3
|
ob.CanSpliceCopy = 3
|
||||||
|
|
||||||
rec := h.server
|
var rec *protocol.ServerSpec
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
|
||||||
err := retry.ExponentialBackoff(5, 200).On(func() error {
|
err := retry.ExponentialBackoff(5, 200).On(func() error {
|
||||||
rawConn, err := dialer.Dial(ctx, rec.Destination)
|
rec = h.serverPicker.PickServer()
|
||||||
|
rawConn, err := dialer.Dial(ctx, rec.Destination())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
target := ob.Target
|
target := ob.Target
|
||||||
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
|
||||||
|
|
||||||
command := protocol.RequestCommandTCP
|
command := protocol.RequestCommandTCP
|
||||||
if target.Network == net.Network_UDP {
|
if target.Network == net.Network_UDP {
|
||||||
@@ -92,7 +95,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
command = protocol.RequestCommandMux
|
command = protocol.RequestCommandMux
|
||||||
}
|
}
|
||||||
|
|
||||||
user := rec.User
|
user := rec.PickUser()
|
||||||
request := &protocol.RequestHeader{
|
request := &protocol.RequestHeader{
|
||||||
Version: encoding.Version,
|
Version: encoding.Version,
|
||||||
User: user,
|
User: user,
|
||||||
@@ -199,7 +202,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to read header").Base(err)
|
return errors.New("failed to read header").Base(err)
|
||||||
}
|
}
|
||||||
h.handleCommand(rec.Destination, header.Command)
|
h.handleCommand(rec.Destination(), header.Command)
|
||||||
|
|
||||||
bodyReader, err := session.DecodeResponseBody(request, reader)
|
bodyReader, err := session.DecodeResponseBody(request, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -423,16 +423,20 @@ func TestCommanderAddRemoveUser(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: u2.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: u2.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -596,16 +600,20 @@ func TestCommanderStats(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -94,13 +94,17 @@ func TestDokodemoTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -186,13 +190,17 @@ func TestDokodemoUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -170,13 +170,17 @@ func TestProxy(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: serverUserID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: serverUserID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -189,13 +193,17 @@ func TestProxy(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Tag: "proxy",
|
Tag: "proxy",
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(proxyPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(proxyPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: proxyUserID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: proxyUserID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -300,13 +308,17 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: serverUserID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: serverUserID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -322,13 +334,17 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Tag: "proxy",
|
Tag: "proxy",
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(proxyPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(proxyPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: proxyUserID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: proxyUserID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -669,16 +685,20 @@ func TestDialXray(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -119,16 +119,20 @@ func TestVMessClosing(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -219,16 +223,20 @@ func TestZeroBuffer(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -155,16 +155,20 @@ func TestReverseProxy(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Tag: "reverse",
|
Tag: "reverse",
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(reversePort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(reversePort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -344,16 +348,20 @@ func TestReverseProxyLongRunning(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Tag: "reverse",
|
Tag: "reverse",
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(reversePort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(reversePort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -75,11 +75,15 @@ func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: account,
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -167,11 +171,15 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: account,
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -260,11 +268,15 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: account,
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -358,11 +370,15 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: account,
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -439,11 +455,15 @@ func TestShadowsocksNone(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: account,
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -73,14 +73,18 @@ func TestSocksBridgeTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&socks.Account{
|
User: []*protocol.User{
|
||||||
Username: "Test Account",
|
{
|
||||||
Password: "Test Password",
|
Account: serial.ToTypedMessage(&socks.Account{
|
||||||
}),
|
Username: "Test Account",
|
||||||
|
Password: "Test Password",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -148,14 +152,18 @@ func TestSocksWithHttpRequest(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&http.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&http.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&http.Account{
|
User: []*protocol.User{
|
||||||
Username: "Test Account",
|
{
|
||||||
Password: "Test Password",
|
Account: serial.ToTypedMessage(&http.Account{
|
||||||
}),
|
Username: "Test Account",
|
||||||
|
Password: "Test Password",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -248,14 +256,18 @@ func TestSocksBridageUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&socks.Account{
|
User: []*protocol.User{
|
||||||
Username: "Test Account",
|
{
|
||||||
Password: "Test Password",
|
Account: serial.ToTypedMessage(&socks.Account{
|
||||||
}),
|
Username: "Test Account",
|
||||||
|
Password: "Test Password",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -363,9 +375,11 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
|
||||||
Server: &protocol.ServerEndpoint{
|
Server: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
Port: uint32(serverPort),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
+110
-70
@@ -89,13 +89,17 @@ func TestSimpleTLSConnection(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -200,13 +204,17 @@ func TestAutoIssuingCertificate(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -301,13 +309,17 @@ func TestTLSOverKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -397,13 +409,17 @@ func TestTLSOverWebSocket(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -509,13 +525,17 @@ func TestGRPC(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -621,13 +641,17 @@ func TestGRPCMultiMode(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -728,13 +752,17 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -826,13 +854,17 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -923,13 +955,17 @@ func TestUTLSConnectionPinned(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -1022,13 +1058,17 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -85,13 +85,17 @@ func TestHTTPConnectionHeader(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
+46
-236
@@ -94,13 +94,17 @@ func TestVless(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -121,212 +125,6 @@ func TestVless(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVlessMuxTcp(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
serverPort := tcp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
|
||||||
Clients: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
|
||||||
Port: uint32(dest.Port),
|
|
||||||
Networks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
|
||||||
MultiplexSettings: &proxyman.MultiplexingConfig{
|
|
||||||
Enabled: true,
|
|
||||||
Concurrency: 4,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Vnext: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
for range "abcd" {
|
|
||||||
var errg errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errg.Go(testTCPConn(clientPort, 10240, time.Second*20))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVlessEncMuxTcp(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
serverPort := tcp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
|
||||||
Clients: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecondsFrom: 600, //mlkem768x25519plus.native.600s.
|
|
||||||
Decryption: "Gzh5Aa3Ibo3343XFC7V2a8ucOpFeGjOL6jMlBZAfjqyty2rdRms8xccBAm68imYw2q96gg2dcueeL2r7n_2YzQ",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
|
||||||
Port: uint32(dest.Port),
|
|
||||||
Networks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
|
||||||
MultiplexSettings: &proxyman.MultiplexingConfig{
|
|
||||||
Enabled: true,
|
|
||||||
Concurrency: 4,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Vnext: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
Seconds: 1, //mlkem768x25519plus.native.0rtt.
|
|
||||||
Encryption: "ExaMB4tIHpFikMeZwAJ8_8hxpZNi3gY13Ft455yC04xiCWgWUwMvKUwDQVm8zLcE8EKnjVlhRDmkTzMzvTMZyYlswCuqx0YK9kVNNFcrQJWD8JpAmTN8fffApIoWitDEAUTEp9S_Ehxo-9a2evRyKqJcQ6WmPiiyGbZrnNAfLKhdRsA15rZt6eKMVQExtDpucfaFc2E4-GtKzKd7P0I6bXccC1q4gqyZcXiEfOmmWBTPMTkNPEUdnQVsPiSWgJxslQZ5pYlPE7GQE7qoxYBItDMhkHZ4l0YwsvgZ1EQ2yTEn9DOxbyMihLk4kSAtg1IrW7tCTNkhyVsUY3SeyReB2sfN2AU-TXmVGUJMTKJ1jfywu8JIb9lG14HB1Rku6nVNcIMTzyshvsi_8AQFCSOcDdQ7ZpBxKxW7N1tKXBI0shq7vWdufjpYCjAVh-k_QgonVOwadYt-wPMxDntbWzEf_yC9eFQ6cBGd5smWNeSQZwAvqXw_WVPD56EVlaQ5HpsOkqBdy1Enr1NnH7WdgNsfk6RSQhRgW1dF9XBUKylpqsvOXkq3I0fLuuJFfuEZu4MeNvdgI2mbM_UxK8AzlRwkm7Eb1WQfm-S05HJefdZzu8kHYamggwtNQum_NtODzRgw3uWbjYbEBIY0j9IMhyGynOYQHHmrR2kT-dh08GwVD7BfsJRvFYgy2ZI8a3xGgHyi6MKKE8g7krEd-ne_4ddSaysgctaiiLwI4NVRbYJIT8XEbmKTIwoZx4R7m7AffYJo2NlfEPREg8stBcY5dAGXeSwD0pxs-jCJOeifQYq7Elq216SrwCmayLg3XJcpxutOmkhai6hRO6eBP6uy9XlLXyMt3TW6isx_rRt1hXCezkl_8hPEcqI9tPE0ZYVQ-eMh2_e35gQyPUw02aequ4ojaHV03QaSMquqF8RXG7k1gDed9vqex3aFaSN6UUNkebLKrqAiPmq0fccQ3qdbAxLGZ0ZFF5mIwEiFoTM6V4yPgntkRYtxcCKK-5YkPfsIunrM3EsWDCovp_Ahdfs-aqQLqzk1wVKTLQaQI5ApBlmGB3EauNdHFJBoeGZOF9e7QbGujhGRGMpS1fFtI2SqlcXINZU7YvR2JMfBrvBYZ9whXawM_Rg31IJR1raMGAEm6hNpa7SBD0cprIZxG6HKUQFMGHVlVohjwpWE5AGIc5Rc8Va2x8e3zFTMTUIwCdMz1XlNaqBMldJx01JQLwgSsnfGGlEJ_jYujvYNo0EBk4yev1Ap6nO-zSU-WtimlhEP0-cb22Q6e4wCEnWfO-lABJsrhwhrbloM51k5QVIefNyIvDWBszpRsreidUZVU4TOH2EoltYslWdPkcckfCplFLyvGKBItoAPRTOKRCjOsqlmj9OvpbDCzedZUmjLNfoLSwsPC7Nk2FpIkVUG6WxCE2YiU9LFrZIgWRKwUluM_at9w7wowRkujXEAQiJKtuUWQCxGyVbJtufLmQI6_yafmwgLoSlyE0cL-_Rf4nBCBjJnmyBDRvAoA-W08vw53uMt3RnFVwKFqo3PonmYAETv5rrMjh3L3K16QS-2EgL_R7WAFd0",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
for range "abcd" {
|
|
||||||
var errg errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errg.Go(testTCPConn(clientPort, 10240, time.Second*20))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVlessTls(t *testing.T) {
|
func TestVlessTls(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
@@ -401,13 +199,17 @@ func TestVlessTls(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
}),
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -520,14 +322,18 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
Flow: vless.XRV,
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
}),
|
Id: userID.String(),
|
||||||
|
Flow: vless.XRV,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -650,14 +456,18 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Vnext: &protocol.ServerEndpoint{
|
Vnext: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
Flow: vless.XRV,
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
}),
|
Id: userID.String(),
|
||||||
|
Flow: vless.XRV,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
+300
-111
@@ -26,6 +26,147 @@ import (
|
|||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestVMessDynamicPort(t *testing.T) {
|
||||||
|
tcpServer := tcp.Server{
|
||||||
|
MsgProcessor: xor,
|
||||||
|
}
|
||||||
|
dest, err := tcpServer.Start()
|
||||||
|
common.Must(err)
|
||||||
|
defer tcpServer.Close()
|
||||||
|
|
||||||
|
userID := protocol.NewID(uuid.New())
|
||||||
|
|
||||||
|
retry := 1
|
||||||
|
serverPort := tcp.PickPort()
|
||||||
|
for {
|
||||||
|
serverConfig := &core.Config{
|
||||||
|
App: []*serial.TypedMessage{
|
||||||
|
serial.ToTypedMessage(&log.Config{
|
||||||
|
ErrorLogLevel: clog.Severity_Debug,
|
||||||
|
ErrorLogType: log.LogType_Console,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
|
{
|
||||||
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
||||||
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
}),
|
||||||
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Detour: &inbound.DetourConfig{
|
||||||
|
To: "detour",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort + 100)}},
|
||||||
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
}),
|
||||||
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
|
Address: net.NewIPOrDomain(dest.Address),
|
||||||
|
Port: uint32(dest.Port),
|
||||||
|
Networks: []net.Network{net.Network_TCP},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
|
PortList: &net.PortList{
|
||||||
|
Range: []*net.PortRange{{From: uint32(serverPort + 1), To: uint32(serverPort + 99)}},
|
||||||
|
},
|
||||||
|
|
||||||
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
AllocationStrategy: &proxyman.AllocationStrategy{
|
||||||
|
Type: proxyman.AllocationStrategy_Random,
|
||||||
|
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
|
||||||
|
Value: 2,
|
||||||
|
},
|
||||||
|
Refresh: &proxyman.AllocationStrategy_AllocationStrategyRefresh{
|
||||||
|
Value: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{}),
|
||||||
|
Tag: "detour",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
|
{
|
||||||
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
server, _ := InitializeServerConfig(serverConfig)
|
||||||
|
if server != nil && WaitConnAvailableWithTest(t, testTCPConn(serverPort+100, 1024, time.Second*2)) {
|
||||||
|
defer CloseServer(server)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
retry += 1
|
||||||
|
if retry > 5 {
|
||||||
|
t.Fatal("All attempts failed to start server")
|
||||||
|
}
|
||||||
|
serverPort = tcp.PickPort()
|
||||||
|
}
|
||||||
|
|
||||||
|
clientPort := tcp.PickPort()
|
||||||
|
clientConfig := &core.Config{
|
||||||
|
App: []*serial.TypedMessage{
|
||||||
|
serial.ToTypedMessage(&log.Config{
|
||||||
|
ErrorLogLevel: clog.Severity_Debug,
|
||||||
|
ErrorLogType: log.LogType_Console,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
|
{
|
||||||
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
||||||
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
}),
|
||||||
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
|
Address: net.NewIPOrDomain(dest.Address),
|
||||||
|
Port: uint32(dest.Port),
|
||||||
|
Networks: []net.Network{net.Network_TCP},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
|
{
|
||||||
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
|
{
|
||||||
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
|
Port: uint32(serverPort),
|
||||||
|
User: []*protocol.User{
|
||||||
|
{
|
||||||
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: userID.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := InitializeServerConfig(clientConfig)
|
||||||
|
common.Must(err)
|
||||||
|
defer CloseServer(server)
|
||||||
|
|
||||||
|
if !WaitConnAvailableWithTest(t, testTCPConn(clientPort, 1024, time.Second*2)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVMessGCM(t *testing.T) {
|
func TestVMessGCM(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
@@ -91,16 +232,20 @@ func TestVMessGCM(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -189,16 +334,20 @@ func TestVMessGCMReadv(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -290,16 +439,20 @@ func TestVMessGCMUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -385,16 +538,20 @@ func TestVMessChacha20(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_CHACHA20_POLY1305,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_CHACHA20_POLY1305,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -481,16 +638,20 @@ func TestVMessNone(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_NONE,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_NONE,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -579,16 +740,20 @@ func TestVMessKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -701,16 +866,20 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -830,16 +999,20 @@ func TestVMessGCMMux(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -953,16 +1126,20 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -1056,16 +1233,20 @@ func TestVMessZero(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_ZERO,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_ZERO,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -1151,17 +1332,21 @@ func TestVMessGCMLengthAuth(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
TestsEnabled: "AuthenticatedLength",
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
TestsEnabled: "AuthenticatedLength",
|
},
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -1213,7 +1398,7 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
TestsEnabled: "AuthenticatedLength|",
|
TestsEnabled: "AuthenticatedLength|NoTerminationSignal",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1251,17 +1436,21 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: []*protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
{
|
||||||
Port: uint32(serverPort),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
User: &protocol.User{
|
Port: uint32(serverPort),
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
User: []*protocol.User{
|
||||||
Id: userID.String(),
|
{
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Id: userID.String(),
|
||||||
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
|
},
|
||||||
|
TestsEnabled: "AuthenticatedLength|NoTerminationSignal",
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
TestsEnabled: "AuthenticatedLength|NoTerminationSignal",
|
},
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user