mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-15 09:34:00 +08:00
VLESS protocol: Add Reverse Proxy (4) Command and extremely simple config (#5101)
https://github.com/XTLS/Xray-core/issues/5088#issuecomment-3263093341
This commit is contained in:
@@ -21,6 +21,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
||||
XorMode: a.XorMode,
|
||||
Seconds: a.Seconds,
|
||||
Padding: a.Padding,
|
||||
Reverse: a.Reverse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -35,6 +36,8 @@ type MemoryAccount struct {
|
||||
XorMode uint32
|
||||
Seconds uint32
|
||||
Padding string
|
||||
|
||||
Reverse *Reverse
|
||||
}
|
||||
|
||||
// Equals implements protocol.Account.Equals().
|
||||
@@ -54,5 +57,6 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
||||
XorMode: a.XorMode,
|
||||
Seconds: a.Seconds,
|
||||
Padding: a.Padding,
|
||||
Reverse: a.Reverse,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,51 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Reverse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Reverse) Reset() {
|
||||
*x = Reverse{}
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Reverse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Reverse) ProtoMessage() {}
|
||||
|
||||
func (x *Reverse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
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 Reverse.ProtoReflect.Descriptor instead.
|
||||
func (*Reverse) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Reverse) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -28,16 +73,17 @@ type Account struct {
|
||||
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
// Flow settings. May be "xtls-rprx-vision".
|
||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||
Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"`
|
||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||
Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"`
|
||||
Reverse *Reverse `protobuf:"bytes,7,opt,name=reverse,proto3" json:"reverse,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Account) Reset() {
|
||||
*x = Account{}
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -49,7 +95,7 @@ func (x *Account) String() string {
|
||||
func (*Account) ProtoMessage() {}
|
||||
|
||||
func (x *Account) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -62,7 +108,7 @@ func (x *Account) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
|
||||
func (*Account) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Account) GetId() string {
|
||||
@@ -107,28 +153,40 @@ func (x *Account) GetPadding() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetReverse() *Reverse {
|
||||
if x != nil {
|
||||
return x.Reverse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proxy_vless_account_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proxy_vless_account_proto_rawDesc = []byte{
|
||||
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x9b, 0x01,
|
||||
0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a,
|
||||
0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
|
||||
0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e,
|
||||
0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
|
||||
0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x52, 0x0a, 0x14, 0x63,
|
||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c,
|
||||
0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 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, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x10, 0x58,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x1b, 0x0a,
|
||||
0x07, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xd0, 0x01, 0x0a, 0x07, 0x41,
|
||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x78, 0x6f,
|
||||
0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x78, 0x6f, 0x72,
|
||||
0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x65,
|
||||
0x72, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x52, 0x65, 0x76,
|
||||
0x65, 0x72, 0x73, 0x65, 0x52, 0x07, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x42, 0x52, 0x0a,
|
||||
0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||
0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 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, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02,
|
||||
0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73,
|
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -143,16 +201,18 @@ func file_proxy_vless_account_proto_rawDescGZIP() []byte {
|
||||
return file_proxy_vless_account_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_proxy_vless_account_proto_goTypes = []any{
|
||||
(*Account)(nil), // 0: xray.proxy.vless.Account
|
||||
(*Reverse)(nil), // 0: xray.proxy.vless.Reverse
|
||||
(*Account)(nil), // 1: xray.proxy.vless.Account
|
||||
}
|
||||
var file_proxy_vless_account_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
0, // 0: xray.proxy.vless.Account.reverse:type_name -> xray.proxy.vless.Reverse
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proxy_vless_account_proto_init() }
|
||||
@@ -166,7 +226,7 @@ func file_proxy_vless_account_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proxy_vless_account_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -6,6 +6,10 @@ option go_package = "github.com/xtls/xray-core/proxy/vless";
|
||||
option java_package = "com.xray.proxy.vless";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Reverse {
|
||||
string tag = 1;
|
||||
}
|
||||
|
||||
message Account {
|
||||
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
||||
string id = 1;
|
||||
@@ -16,4 +20,6 @@ message Account {
|
||||
uint32 xorMode = 4;
|
||||
uint32 seconds = 5;
|
||||
string padding = 6;
|
||||
|
||||
Reverse reverse = 7;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
|
||||
return errors.New("failed to write request command").Base(err)
|
||||
}
|
||||
|
||||
if request.Command != protocol.RequestCommandMux {
|
||||
if request.Command != protocol.RequestCommandMux && request.Command != protocol.RequestCommandRvs {
|
||||
if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
|
||||
return errors.New("failed to write request address and port").Base(err)
|
||||
}
|
||||
@@ -112,7 +112,8 @@ func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validat
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandMux:
|
||||
request.Address = net.DomainAddress("v1.mux.cool")
|
||||
request.Port = 0
|
||||
case protocol.RequestCommandRvs:
|
||||
request.Address = net.DomainAddress("v1.rvs.cool")
|
||||
case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
|
||||
if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil {
|
||||
request.Address = addr
|
||||
|
||||
@@ -12,19 +12,24 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/app/reverse"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/retry"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"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/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
feature_inbound "github.com/xtls/xray-core/features/inbound"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
@@ -66,12 +71,14 @@ func init() {
|
||||
|
||||
// Handler is an inbound connection handler that handles messages in VLess protocol.
|
||||
type Handler struct {
|
||||
inboundHandlerManager feature_inbound.Manager
|
||||
policyManager policy.Manager
|
||||
validator vless.Validator
|
||||
dns dns.Client
|
||||
decryption *encryption.ServerInstance
|
||||
fallbacks map[string]map[string]map[string]*Fallback // or nil
|
||||
inboundHandlerManager feature_inbound.Manager
|
||||
policyManager policy.Manager
|
||||
validator vless.Validator
|
||||
decryption *encryption.ServerInstance
|
||||
outboundHandlerManager outbound.Manager
|
||||
defaultDispatcher *dispatcher.DefaultDispatcher
|
||||
ctx context.Context
|
||||
fallbacks map[string]map[string]map[string]*Fallback // or nil
|
||||
// regexps map[string]*regexp.Regexp // or nil
|
||||
}
|
||||
|
||||
@@ -79,10 +86,12 @@ type Handler struct {
|
||||
func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Validator) (*Handler, error) {
|
||||
v := core.MustFromContext(ctx)
|
||||
handler := &Handler{
|
||||
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
|
||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||
dns: dc,
|
||||
validator: validator,
|
||||
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
|
||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||
validator: validator,
|
||||
outboundHandlerManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
|
||||
defaultDispatcher: v.GetFeature(routing.DispatcherType()).(*dispatcher.DefaultDispatcher),
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
if config.Decryption != "" && config.Decryption != "none" {
|
||||
@@ -174,11 +183,49 @@ func isMuxAndNotXUDP(request *protocol.RequestHeader, first *buf.Buffer) bool {
|
||||
firstBytes[6] == 2) // Network type: UDP
|
||||
}
|
||||
|
||||
func (h *Handler) GetReverse(a *vless.MemoryAccount) (*Reverse, error) {
|
||||
u := h.validator.Get(a.ID.UUID())
|
||||
if u == nil {
|
||||
return nil, errors.New("reverse: user " + a.ID.String() + " doesn't exist anymore")
|
||||
}
|
||||
a = u.Account.(*vless.MemoryAccount)
|
||||
if a.Reverse == nil || a.Reverse.Tag == "" {
|
||||
return nil, errors.New("reverse: user " + a.ID.String() + " is not allowed to create reverse proxy")
|
||||
}
|
||||
r := h.outboundHandlerManager.GetHandler(a.Reverse.Tag)
|
||||
if r == nil {
|
||||
picker, _ := reverse.NewStaticMuxPicker()
|
||||
r = &Reverse{tag: a.Reverse.Tag, picker: picker, client: &mux.ClientManager{Picker: picker}}
|
||||
for len(h.outboundHandlerManager.ListHandlers(h.ctx)) == 0 {
|
||||
time.Sleep(time.Second) // prevents this outbound from becoming the default outbound
|
||||
}
|
||||
if err := h.outboundHandlerManager.AddHandler(h.ctx, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if r, ok := r.(*Reverse); ok {
|
||||
return r, nil
|
||||
}
|
||||
return nil, errors.New("reverse: outbound " + a.Reverse.Tag + " is not type Reverse")
|
||||
}
|
||||
|
||||
func (h *Handler) RemoveReverse(u *protocol.MemoryUser) {
|
||||
if u != nil {
|
||||
a := u.Account.(*vless.MemoryAccount)
|
||||
if a.Reverse != nil && a.Reverse.Tag != "" {
|
||||
h.outboundHandlerManager.RemoveHandler(h.ctx, a.Reverse.Tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close implements common.Closable.Close().
|
||||
func (h *Handler) Close() error {
|
||||
if h.decryption != nil {
|
||||
h.decryption.Close()
|
||||
}
|
||||
for _, u := range h.validator.GetAll() {
|
||||
h.RemoveReverse(u)
|
||||
}
|
||||
return errors.Combine(common.Close(h.validator))
|
||||
}
|
||||
|
||||
@@ -189,6 +236,7 @@ func (h *Handler) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
|
||||
|
||||
// RemoveUser implements proxy.UserManager.RemoveUser().
|
||||
func (h *Handler) RemoveUser(ctx context.Context, e string) error {
|
||||
h.RemoveReverse(h.validator.GetByEmail(e))
|
||||
return h.validator.Del(e)
|
||||
}
|
||||
|
||||
@@ -500,7 +548,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandUDP:
|
||||
return errors.New(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
||||
case protocol.RequestCommandMux:
|
||||
case protocol.RequestCommandMux, protocol.RequestCommandRvs:
|
||||
inbound.CanSpliceCopy = 3
|
||||
fallthrough // we will break Mux connections that contain TCP requests
|
||||
case protocol.RequestCommandTCP:
|
||||
var t reflect.Type
|
||||
@@ -565,6 +614,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
|
||||
bufferWriter.SetFlushNext()
|
||||
|
||||
if request.Command == protocol.RequestCommandRvs {
|
||||
r, err := h.GetReverse(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.NewMux(ctx, h.defaultDispatcher.WrapLink(ctx, &transport.Link{Reader: clientReader, Writer: clientWriter}))
|
||||
}
|
||||
|
||||
if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{
|
||||
Reader: clientReader,
|
||||
Writer: clientWriter},
|
||||
@@ -573,3 +630,58 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Reverse struct {
|
||||
tag string
|
||||
picker *reverse.StaticMuxPicker
|
||||
client *mux.ClientManager
|
||||
}
|
||||
|
||||
func (r *Reverse) Tag() string {
|
||||
return r.tag
|
||||
}
|
||||
|
||||
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link) error {
|
||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||
if err != nil {
|
||||
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
||||
}
|
||||
worker, err := reverse.NewPortalWorker(muxClient)
|
||||
if err != nil {
|
||||
return errors.New("failed to create portal worker").Base(err).AtWarning()
|
||||
}
|
||||
r.picker.AddWorker(worker)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-muxClient.WaitClosed():
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reverse) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if ob != nil {
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
}
|
||||
r.client.Dispatch(ctx, link)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reverse) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reverse) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reverse) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reverse) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
proxyman "github.com/xtls/xray-core/app/proxyman/outbound"
|
||||
"github.com/xtls/xray-core/app/reverse"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/retry"
|
||||
@@ -23,6 +26,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/xudp"
|
||||
"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/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/proxy/vless/encoding"
|
||||
@@ -32,6 +36,7 @@ import (
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -47,6 +52,7 @@ type Handler struct {
|
||||
policyManager policy.Manager
|
||||
cone bool
|
||||
encryption *encryption.ClientInstance
|
||||
reverse *Reverse
|
||||
}
|
||||
|
||||
// New creates a new VLess outbound handler.
|
||||
@@ -82,14 +88,39 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if a.Reverse != nil {
|
||||
handler.reverse = &Reverse{
|
||||
tag: a.Reverse.Tag,
|
||||
dispatcher: v.GetFeature(routing.DispatcherType()).(routing.Dispatcher),
|
||||
ctx: ctx,
|
||||
handler: handler,
|
||||
}
|
||||
handler.reverse.monitorTask = &task.Periodic{
|
||||
Execute: handler.reverse.monitor,
|
||||
Interval: time.Second * 2,
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
handler.reverse.Start()
|
||||
}()
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
// Close implements common.Closable.Close().
|
||||
func (h *Handler) Close() error {
|
||||
if h.reverse != nil {
|
||||
return h.reverse.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process implements proxy.Outbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if !ob.Target.IsValid() {
|
||||
if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
|
||||
return errors.New("target not specified").AtError()
|
||||
}
|
||||
ob.Name = "vless"
|
||||
@@ -127,8 +158,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
if target.Network == net.Network_UDP {
|
||||
command = protocol.RequestCommandUDP
|
||||
}
|
||||
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
|
||||
command = protocol.RequestCommandMux
|
||||
if target.Address.Family().IsDomain() {
|
||||
switch target.Address.Domain() {
|
||||
case "v1.mux.cool":
|
||||
command = protocol.RequestCommandMux
|
||||
case "v1.rvs.cool":
|
||||
if target.Network != net.Network_Unknown {
|
||||
return errors.New("nice try baby").AtError()
|
||||
}
|
||||
command = protocol.RequestCommandRvs
|
||||
}
|
||||
}
|
||||
|
||||
request := &protocol.RequestHeader{
|
||||
@@ -321,3 +360,67 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Reverse struct {
|
||||
tag string
|
||||
dispatcher routing.Dispatcher
|
||||
ctx context.Context
|
||||
handler *Handler
|
||||
workers []*reverse.BridgeWorker
|
||||
monitorTask *task.Periodic
|
||||
}
|
||||
|
||||
func (r *Reverse) monitor() error {
|
||||
var activeWorkers []*reverse.BridgeWorker
|
||||
for _, w := range r.workers {
|
||||
if w.IsActive() {
|
||||
activeWorkers = append(activeWorkers, w)
|
||||
}
|
||||
}
|
||||
if len(activeWorkers) != len(r.workers) {
|
||||
r.workers = activeWorkers
|
||||
}
|
||||
|
||||
var numConnections uint32
|
||||
var numWorker uint32
|
||||
for _, w := range r.workers {
|
||||
if w.IsActive() {
|
||||
numConnections += w.Connections()
|
||||
numWorker++
|
||||
}
|
||||
}
|
||||
if numWorker == 0 || numConnections/numWorker > 16 {
|
||||
reader1, writer1 := pipe.New(pipe.WithSizeLimit(2 * buf.Size))
|
||||
reader2, writer2 := pipe.New(pipe.WithSizeLimit(2 * buf.Size))
|
||||
link1 := &transport.Link{Reader: reader1, Writer: writer2}
|
||||
link2 := &transport.Link{Reader: reader2, Writer: writer1}
|
||||
w := &reverse.BridgeWorker{
|
||||
Tag: r.tag,
|
||||
Dispatcher: r.dispatcher,
|
||||
}
|
||||
worker, err := mux.NewServerWorker(r.ctx, w, link1)
|
||||
if err != nil {
|
||||
errors.LogWarningInner(r.ctx, err, "failed to create mux server worker")
|
||||
return nil
|
||||
}
|
||||
w.Worker = worker
|
||||
r.workers = append(r.workers, w)
|
||||
go func() {
|
||||
ctx := session.ContextWithOutbounds(r.ctx, []*session.Outbound{{
|
||||
Target: net.Destination{Address: net.DomainAddress("v1.rvs.cool")},
|
||||
}})
|
||||
r.handler.Process(ctx, link2, session.HandlerFromContext(ctx).(*proxyman.Handler))
|
||||
common.Interrupt(reader1)
|
||||
common.Interrupt(reader2)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reverse) Start() error {
|
||||
return r.monitorTask.Start()
|
||||
}
|
||||
|
||||
func (r *Reverse) Close() error {
|
||||
return r.monitorTask.Close()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user