Compare commits

...

10 Commits

Author SHA1 Message Date
yuhan6665
43779f379f Experiment: seed ignore buffer and send 1st fake packet instantly 2025-09-07 09:48:21 -04:00
yuhan6665
082fecf334 Add quick logic for scheduler to send fake packet when no buffer is pending 2025-09-07 09:37:44 -04:00
yuhan6665
7299cfc56f Add VLESS seed tests 2025-09-07 09:36:46 -04:00
yuhan6665
0e206b99bd Add proxy Scheduler 2025-09-07 09:33:58 -04:00
yuhan6665
45f677a538 Fill vless response addon 2025-09-07 09:31:14 -04:00
yuhan6665
b6afe68d84 Add seed padding logic
- Seed is decoupled with XTLS Vision, which means Seed can turn on without flow
- XTLS Vision now use Seed config to configure its padding only mode
2025-09-07 09:28:24 -04:00
yuhan6665
51234fbe53 Collect stats and possible padding (previously Vision Reader Writer) to all traffic 2025-09-07 09:12:48 -04:00
yuhan6665
cba71f8cdc Add more traffic info for future use 2025-09-05 21:49:55 -04:00
yuhan6665
279abd4fc8 Populate Seed (more TBD) and checks 2025-09-05 21:33:31 -04:00
yuhan6665
b1f4d32ef0 Add VLESS seed configurations 2025-09-05 21:29:11 -04:00
15 changed files with 1567 additions and 166 deletions

512
proxy/addons.pb.go Normal file
View File

@@ -0,0 +1,512 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v4.23.1
// source: proxy/addons.proto
package proxy
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SeedMode int32
const (
SeedMode_Unknown SeedMode = 0
SeedMode_PaddingOnly SeedMode = 1
SeedMode_PaddingPlusDelay SeedMode = 2
SeedMode_IndependentScheduler SeedMode = 3
)
// Enum value maps for SeedMode.
var (
SeedMode_name = map[int32]string{
0: "Unknown",
1: "PaddingOnly",
2: "PaddingPlusDelay",
3: "IndependentScheduler",
}
SeedMode_value = map[string]int32{
"Unknown": 0,
"PaddingOnly": 1,
"PaddingPlusDelay": 2,
"IndependentScheduler": 3,
}
)
func (x SeedMode) Enum() *SeedMode {
p := new(SeedMode)
*p = x
return p
}
func (x SeedMode) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (SeedMode) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_addons_proto_enumTypes[0].Descriptor()
}
func (SeedMode) Type() protoreflect.EnumType {
return &file_proxy_addons_proto_enumTypes[0]
}
func (x SeedMode) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use SeedMode.Descriptor instead.
func (SeedMode) EnumDescriptor() ([]byte, []int) {
return file_proxy_addons_proto_rawDescGZIP(), []int{0}
}
type Addons struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
Mode SeedMode `protobuf:"varint,3,opt,name=Mode,proto3,enum=xray.proxy.SeedMode" json:"Mode,omitempty"`
Duration string `protobuf:"bytes,4,opt,name=Duration,proto3" json:"Duration,omitempty"` // "0-8" means apply to number of packets, "1000b-" means start applying once both side exchange 1kb data, counting two-ways
Padding *PaddingConfig `protobuf:"bytes,5,opt,name=Padding,proto3" json:"Padding,omitempty"`
Delay *DelayConfig `protobuf:"bytes,6,opt,name=Delay,proto3" json:"Delay,omitempty"`
Scheduler *SchedulerConfig `protobuf:"bytes,7,opt,name=Scheduler,proto3" json:"Scheduler,omitempty"`
}
func (x *Addons) Reset() {
*x = Addons{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_addons_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Addons) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Addons) ProtoMessage() {}
func (x *Addons) ProtoReflect() protoreflect.Message {
mi := &file_proxy_addons_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Addons.ProtoReflect.Descriptor instead.
func (*Addons) Descriptor() ([]byte, []int) {
return file_proxy_addons_proto_rawDescGZIP(), []int{0}
}
func (x *Addons) GetFlow() string {
if x != nil {
return x.Flow
}
return ""
}
func (x *Addons) GetSeed() []byte {
if x != nil {
return x.Seed
}
return nil
}
func (x *Addons) GetMode() SeedMode {
if x != nil {
return x.Mode
}
return SeedMode_Unknown
}
func (x *Addons) GetDuration() string {
if x != nil {
return x.Duration
}
return ""
}
func (x *Addons) GetPadding() *PaddingConfig {
if x != nil {
return x.Padding
}
return nil
}
func (x *Addons) GetDelay() *DelayConfig {
if x != nil {
return x.Delay
}
return nil
}
func (x *Addons) GetScheduler() *SchedulerConfig {
if x != nil {
return x.Scheduler
}
return nil
}
type PaddingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RegularMin uint32 `protobuf:"varint,1,opt,name=RegularMin,proto3" json:"RegularMin,omitempty"`
RegularMax uint32 `protobuf:"varint,2,opt,name=RegularMax,proto3" json:"RegularMax,omitempty"`
LongMin uint32 `protobuf:"varint,3,opt,name=LongMin,proto3" json:"LongMin,omitempty"`
LongMax uint32 `protobuf:"varint,4,opt,name=LongMax,proto3" json:"LongMax,omitempty"`
}
func (x *PaddingConfig) Reset() {
*x = PaddingConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_addons_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PaddingConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PaddingConfig) ProtoMessage() {}
func (x *PaddingConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_addons_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PaddingConfig.ProtoReflect.Descriptor instead.
func (*PaddingConfig) Descriptor() ([]byte, []int) {
return file_proxy_addons_proto_rawDescGZIP(), []int{1}
}
func (x *PaddingConfig) GetRegularMin() uint32 {
if x != nil {
return x.RegularMin
}
return 0
}
func (x *PaddingConfig) GetRegularMax() uint32 {
if x != nil {
return x.RegularMax
}
return 0
}
func (x *PaddingConfig) GetLongMin() uint32 {
if x != nil {
return x.LongMin
}
return 0
}
func (x *PaddingConfig) GetLongMax() uint32 {
if x != nil {
return x.LongMax
}
return 0
}
type DelayConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsRandom bool `protobuf:"varint,1,opt,name=IsRandom,proto3" json:"IsRandom,omitempty"`
MinMillis uint32 `protobuf:"varint,2,opt,name=MinMillis,proto3" json:"MinMillis,omitempty"`
MaxMillis uint32 `protobuf:"varint,3,opt,name=MaxMillis,proto3" json:"MaxMillis,omitempty"`
}
func (x *DelayConfig) Reset() {
*x = DelayConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_addons_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DelayConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DelayConfig) ProtoMessage() {}
func (x *DelayConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_addons_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DelayConfig.ProtoReflect.Descriptor instead.
func (*DelayConfig) Descriptor() ([]byte, []int) {
return file_proxy_addons_proto_rawDescGZIP(), []int{2}
}
func (x *DelayConfig) GetIsRandom() bool {
if x != nil {
return x.IsRandom
}
return false
}
func (x *DelayConfig) GetMinMillis() uint32 {
if x != nil {
return x.MinMillis
}
return 0
}
func (x *DelayConfig) GetMaxMillis() uint32 {
if x != nil {
return x.MaxMillis
}
return 0
}
type SchedulerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TimeoutMillis uint32 `protobuf:"varint,1,opt,name=TimeoutMillis,proto3" json:"TimeoutMillis,omitempty"` // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
}
func (x *SchedulerConfig) Reset() {
*x = SchedulerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_addons_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SchedulerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SchedulerConfig) ProtoMessage() {}
func (x *SchedulerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_addons_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SchedulerConfig.ProtoReflect.Descriptor instead.
func (*SchedulerConfig) Descriptor() ([]byte, []int) {
return file_proxy_addons_proto_rawDescGZIP(), []int{3}
}
func (x *SchedulerConfig) GetTimeoutMillis() uint32 {
if x != nil {
return x.TimeoutMillis
}
return 0
}
var File_proxy_addons_proto protoreflect.FileDescriptor
var file_proxy_addons_proto_rawDesc = []byte{
0x0a, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x22, 0x95, 0x02, 0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46,
0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12,
0x12, 0x0a, 0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53,
0x65, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x14, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53,
0x65, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a,
0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x07, 0x50, 0x61, 0x64,
0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x2d,
0x0a, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x39, 0x0a,
0x09, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x63,
0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x53,
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x64,
0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65,
0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65,
0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f,
0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e,
0x67, 0x4d, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x22, 0x65,
0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a,
0x08, 0x49, 0x73, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x08, 0x49, 0x73, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x69, 0x6e,
0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x69,
0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69,
0x6c, 0x6c, 0x69, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x61, 0x78, 0x4d,
0x69, 0x6c, 0x6c, 0x69, 0x73, 0x22, 0x37, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x2a, 0x58,
0x0a, 0x08, 0x53, 0x65, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e,
0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x64, 0x64, 0x69,
0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x61, 0x64, 0x64,
0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x73, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x10, 0x02, 0x12, 0x18,
0x0a, 0x14, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x68,
0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x10, 0x03, 0x42, 0x40, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x01, 0x5a, 0x1f, 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, 0xaa, 0x02, 0x0a,
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_proxy_addons_proto_rawDescOnce sync.Once
file_proxy_addons_proto_rawDescData = file_proxy_addons_proto_rawDesc
)
func file_proxy_addons_proto_rawDescGZIP() []byte {
file_proxy_addons_proto_rawDescOnce.Do(func() {
file_proxy_addons_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_addons_proto_rawDescData)
})
return file_proxy_addons_proto_rawDescData
}
var file_proxy_addons_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proxy_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_addons_proto_goTypes = []interface{}{
(SeedMode)(0), // 0: xray.proxy.SeedMode
(*Addons)(nil), // 1: xray.proxy.Addons
(*PaddingConfig)(nil), // 2: xray.proxy.PaddingConfig
(*DelayConfig)(nil), // 3: xray.proxy.DelayConfig
(*SchedulerConfig)(nil), // 4: xray.proxy.SchedulerConfig
}
var file_proxy_addons_proto_depIdxs = []int32{
0, // 0: xray.proxy.Addons.Mode:type_name -> xray.proxy.SeedMode
2, // 1: xray.proxy.Addons.Padding:type_name -> xray.proxy.PaddingConfig
3, // 2: xray.proxy.Addons.Delay:type_name -> xray.proxy.DelayConfig
4, // 3: xray.proxy.Addons.Scheduler:type_name -> xray.proxy.SchedulerConfig
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proxy_addons_proto_init() }
func file_proxy_addons_proto_init() {
if File_proxy_addons_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_addons_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Addons); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_addons_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PaddingConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_addons_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DelayConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_addons_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_addons_proto_rawDesc,
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_addons_proto_goTypes,
DependencyIndexes: file_proxy_addons_proto_depIdxs,
EnumInfos: file_proxy_addons_proto_enumTypes,
MessageInfos: file_proxy_addons_proto_msgTypes,
}.Build()
File_proxy_addons_proto = out.File
file_proxy_addons_proto_rawDesc = nil
file_proxy_addons_proto_goTypes = nil
file_proxy_addons_proto_depIdxs = nil
}

42
proxy/addons.proto Normal file
View File

@@ -0,0 +1,42 @@
syntax = "proto3";
package xray.proxy;
option csharp_namespace = "Xray.Proxy";
option go_package = "github.com/xtls/xray-core/proxy";
option java_package = "com.xray.proxy";
option java_multiple_files = true;
message Addons {
string Flow = 1;
bytes Seed = 2;
SeedMode Mode = 3;
string Duration = 4; // "0-8" means apply to number of packets, "1000b-" means start applying once both side exchange 1kb data, counting two-ways
PaddingConfig Padding = 5;
DelayConfig Delay = 6;
SchedulerConfig Scheduler = 7;
}
enum SeedMode {
Unknown = 0;
PaddingOnly = 1;
PaddingPlusDelay = 2;
IndependentScheduler = 3;
}
message PaddingConfig {
uint32 RegularMin = 1;
uint32 RegularMax = 2;
uint32 LongMin = 3;
uint32 LongMax = 4;
}
message DelayConfig {
bool IsRandom = 1;
uint32 MinMillis = 2;
uint32 MaxMillis = 3;
}
message SchedulerConfig {
uint32 TimeoutMillis = 1; // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
// Other TBD
}

View File

@@ -13,6 +13,7 @@ import (
"math/big"
"runtime"
"strconv"
"strings"
"time"
"github.com/pires/go-proxyproto"
@@ -102,6 +103,11 @@ type GetOutbound interface {
// It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
type TrafficState struct {
UserUUID []byte
StartTime time.Time
ByteSent int64
ByteReceived int64
NumberOfPacketSent int
NumberOfPacketReceived int
NumberOfPacketToFilter int
EnableXtls bool
IsTLS12orAbove bool
@@ -138,9 +144,14 @@ type OutboundState struct {
UplinkWriterDirectCopy bool
}
func NewTrafficState(userUUID []byte) *TrafficState {
return &TrafficState{
func NewTrafficState(userUUID []byte, flow string) *TrafficState {
var state = TrafficState{
UserUUID: userUUID,
StartTime: time.Time{},
ByteSent: 0,
ByteReceived: 0,
NumberOfPacketSent: 0,
NumberOfPacketReceived: 0,
NumberOfPacketToFilter: 8,
EnableXtls: false,
IsTLS12orAbove: false,
@@ -148,32 +159,36 @@ func NewTrafficState(userUUID []byte) *TrafficState {
Cipher: 0,
RemainingServerHello: -1,
Inbound: InboundState{
WithinPaddingBuffers: true,
UplinkReaderDirectCopy: false,
RemainingCommand: -1,
RemainingContent: -1,
RemainingPadding: -1,
CurrentCommand: 0,
IsPadding: true,
DownlinkWriterDirectCopy: false,
IsPadding: true,
},
Outbound: OutboundState{
WithinPaddingBuffers: true,
DownlinkReaderDirectCopy: false,
RemainingCommand: -1,
RemainingContent: -1,
RemainingPadding: -1,
CurrentCommand: 0,
IsPadding: true,
UplinkWriterDirectCopy: false,
IsPadding: true,
},
}
if len(flow) > 0 {
state.Inbound.WithinPaddingBuffers = true;
state.Outbound.WithinPaddingBuffers = true;
}
return &state
}
// VisionReader is used to read xtls vision protocol
// VisionReader is used to read seed protocol
// Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
type VisionReader struct {
buf.Reader
addons *Addons
trafficState *TrafficState
ctx context.Context
isUplink bool
@@ -186,9 +201,10 @@ type VisionReader struct {
directReadCounter stats.Counter
}
func NewVisionReader(reader buf.Reader, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) *VisionReader {
func NewVisionReader(reader buf.Reader, addon *Addons, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) *VisionReader {
return &VisionReader{
Reader: reader,
addons: addon,
trafficState: trafficState,
ctx: ctx,
isUplink: isUplink,
@@ -204,6 +220,10 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
if buffer.IsEmpty() {
return buffer, err
}
if w.trafficState.StartTime.IsZero() {
w.trafficState.StartTime = time.Now()
}
w.trafficState.ByteReceived += int64(buffer.Len())
var withinPaddingBuffers *bool
var remainingContent *int32
@@ -231,7 +251,7 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buffer, err
}
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
if *withinPaddingBuffers || w.trafficState.NumberOfPacketReceived <= 8 || !ShouldStopSeed(w.addons, w.trafficState) {
mb2 := make(buf.MultiBuffer, 0, len(buffer))
for _, b := range buffer {
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
@@ -251,6 +271,7 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
}
}
w.trafficState.NumberOfPacketReceived += len(buffer)
if w.trafficState.NumberOfPacketToFilter > 0 {
XtlsFilterTls(buffer, w.trafficState, w.ctx)
}
@@ -283,10 +304,11 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buffer, err
}
// VisionWriter is used to write xtls vision protocol
// VisionWriter is used to write seed protocol
// Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
type VisionWriter struct {
buf.Writer
addons *Addons
trafficState *TrafficState
ctx context.Context
isUplink bool
@@ -294,21 +316,24 @@ type VisionWriter struct {
ob *session.Outbound
// internal
writeOnceUserUUID []byte
writeOnceUserUUID *[]byte
directWriteCounter stats.Counter
scheduler *Scheduler
}
func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound) *VisionWriter {
func NewVisionWriter(writer buf.Writer, addon *Addons, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound) *VisionWriter {
w := make([]byte, len(trafficState.UserUUID))
copy(w, trafficState.UserUUID)
return &VisionWriter{
Writer: writer,
addons: addon,
trafficState: trafficState,
ctx: ctx,
writeOnceUserUUID: w,
writeOnceUserUUID: &w,
isUplink: isUplink,
conn: conn,
ob: ob,
scheduler: NewScheduler(writer, addon, trafficState, &w, ctx),
}
}
@@ -341,49 +366,63 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
w.directWriteCounter.Add(int64(mb.Len()))
}
w.trafficState.NumberOfPacketSent += len(mb)
if w.trafficState.NumberOfPacketToFilter > 0 {
XtlsFilterTls(mb, w.trafficState, w.ctx)
}
if *isPadding {
if *isPadding && ShouldStartSeed(w.addons, w.trafficState) {
if len(mb) == 1 && mb[0] == nil {
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
return w.Writer.WriteMultiBuffer(mb)
}
mb = ReshapeMultiBuffer(w.ctx, mb)
longPadding := w.trafficState.IsTLS
for i, b := range mb {
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
if w.trafficState.EnableXtls {
*switchToDirectCopy = true
mb[0] = XtlsPadding(nil, CommandPaddingContinue, w.writeOnceUserUUID, true, w.addons, w.ctx) // we do a long padding to hide vless header
} else {
mb = ReshapeMultiBuffer(w.ctx, mb)
longPadding := w.trafficState.IsTLS
for i, b := range mb {
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
if w.trafficState.EnableXtls {
*switchToDirectCopy = true
}
var command byte = CommandPaddingContinue
if i == len(mb) - 1 {
if w.trafficState.EnableXtls {
command = CommandPaddingDirect
*isPadding = false
} else if ShouldStopSeed(w.addons, w.trafficState) {
command = CommandPaddingEnd
*isPadding = false
}
}
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, true, w.addons, w.ctx)
longPadding = false
continue
} else if !w.trafficState.IsTLS12orAbove && ShouldStopSeed(w.addons, w.trafficState) {
*isPadding = false
mb[i] = XtlsPadding(b, CommandPaddingEnd, w.writeOnceUserUUID, longPadding, w.addons, w.ctx)
break
}
var command byte = CommandPaddingContinue
if i == len(mb)-1 {
if i == len(mb)-1 && !*isPadding {
command = CommandPaddingEnd
if w.trafficState.EnableXtls {
command = CommandPaddingDirect
}
}
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
*isPadding = false // padding going to end
longPadding = false
continue
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
*isPadding = false
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
break
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, longPadding, w.addons, w.ctx)
}
var command byte = CommandPaddingContinue
if i == len(mb)-1 && !*isPadding {
command = CommandPaddingEnd
if w.trafficState.EnableXtls {
command = CommandPaddingDirect
}
}
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
}
}
return w.Writer.WriteMultiBuffer(mb)
w.trafficState.ByteSent += int64(mb.Len())
if w.trafficState.StartTime.IsZero() {
w.trafficState.StartTime = time.Now()
}
w.scheduler.Buffer <- mb
if w.addons.Scheduler == nil {
w.scheduler.Trigger <- -1 // send all buffers
}
if len(w.scheduler.Error) > 0 {
return <-w.scheduler.Error
}
return nil
}
// ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
@@ -422,24 +461,24 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
}
// XtlsPadding add padding to eliminate length signature during tls handshake
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, addons *Addons, ctx context.Context) *buf.Buffer {
var contentLen int32 = 0
var paddingLen int32 = 0
if b != nil {
contentLen = b.Len()
}
if contentLen < 900 && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(500))
if contentLen < int32(addons.Padding.LongMin) && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(int64(addons.Padding.LongMax - addons.Padding.LongMin)))
if err != nil {
errors.LogDebugInner(ctx, err, "failed to generate padding")
}
paddingLen = int32(l.Int64()) + 900 - contentLen
paddingLen = int32(l.Int64()) + int32(addons.Padding.LongMin) - contentLen
} else {
l, err := rand.Int(rand.Reader, big.NewInt(256))
l, err := rand.Int(rand.Reader, big.NewInt(int64(addons.Padding.RegularMax - addons.Padding.RegularMin)))
if err != nil {
errors.LogDebugInner(ctx, err, "failed to generate padding")
}
paddingLen = int32(l.Int64())
paddingLen = int32(l.Int64()) + int32(addons.Padding.RegularMin)
}
if paddingLen > buf.Size-21-contentLen {
paddingLen = buf.Size - 21 - contentLen
@@ -735,3 +774,50 @@ func IsRAWTransportWithoutSecurity(conn stat.Connection) bool {
_, ok3 := iConn.(*internet.UnixConnWrapper)
return ok1 || ok2 || ok3
}
func ShouldStartSeed(addons *Addons, trafficState *TrafficState) bool {
if len(addons.Duration) == 0 || len(strings.Split(addons.Duration, "-")) < 2 {
return false
}
start := strings.ToLower(strings.Split(addons.Duration, "-")[0])
if len(start) == 0 {
return true
}
if strings.Contains(start, "b") {
start = strings.TrimRight(start, "b")
i, err := strconv.Atoi(start)
if err == nil && i <= int(trafficState.ByteSent + trafficState.ByteSent) {
return true
}
} else {
i, err := strconv.Atoi(start)
if err == nil && i <= trafficState.NumberOfPacketSent + trafficState.NumberOfPacketReceived {
return true
}
}
return false
}
func ShouldStopSeed(addons *Addons, trafficState *TrafficState) bool {
if len(addons.Duration) == 0 || len(strings.Split(addons.Duration, "-")) < 2 {
return true
}
start := strings.ToLower(strings.Split(addons.Duration, "-")[1])
if len(start) == 0 { // infinite
return false
}
if strings.Contains(start, "b") {
start = strings.TrimRight(start, "b")
i, err := strconv.Atoi(start)
if err == nil && i > int(trafficState.ByteSent + trafficState.ByteSent) {
return false
}
} else {
i, err := strconv.Atoi(start)
if err == nil && i > trafficState.NumberOfPacketSent + trafficState.NumberOfPacketReceived {
return false
}
}
return true
}

107
proxy/scheduler.go Normal file
View File

@@ -0,0 +1,107 @@
package proxy
import (
"context"
"crypto/rand"
"math/big"
"sync"
"time"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
)
type Scheduler struct {
Buffer chan buf.MultiBuffer
Trigger chan int
Error chan error
closed chan int
bufferReadLock *sync.Mutex
writer buf.Writer
addons *Addons
trafficState *TrafficState
writeOnceUserUUID *[]byte
ctx context.Context
}
func NewScheduler(w buf.Writer, addon *Addons, state *TrafficState, userUUID *[]byte, context context.Context) *Scheduler {
var s = Scheduler{
Buffer: make(chan buf.MultiBuffer, 100),
Trigger: make(chan int),
Error: make(chan error, 100),
closed: make(chan int),
bufferReadLock: new(sync.Mutex),
writer: w,
addons: addon,
trafficState: state,
writeOnceUserUUID: userUUID,
ctx: context,
}
go s.mainLoop()
if s.addons.Scheduler != nil {
go s.exampleIndependentScheduler()
}
return &s
}
func(s *Scheduler) mainLoop() {
for trigger := range s.Trigger {
if len(s.closed) > 0 {
return
}
go func() { // each trigger has independent delay, trigger does not block
var d = 0 * time.Millisecond
if s.addons.Delay != nil {
l, err := rand.Int(rand.Reader, big.NewInt(int64(s.addons.Delay.MaxMillis - s.addons.Delay.MinMillis)))
if err != nil {
errors.LogWarningInner(s.ctx, err, "failed to generate delay", trigger)
}
d = time.Duration(uint32(l.Int64()) + s.addons.Delay.MinMillis) * time.Millisecond
time.Sleep(d)
}
s.bufferReadLock.Lock() // guard against multiple trigger threads
var sending = len(s.Buffer)
if sending > 0 {
errors.LogDebug(s.ctx, "Scheduler Trigger for ", sending, " buffer(s) with ", d, " ", trigger)
for i := 0; i<sending; i++ {
err := s.writer.WriteMultiBuffer(<-s.Buffer)
if err != nil {
s.Error <- err
s.closed <- 1
return
}
}
} else if trigger > 0 && (s.trafficState.Inbound.IsPadding || s.trafficState.Outbound.IsPadding) && ShouldStartSeed(s.addons, s.trafficState) && !ShouldStopSeed(s.addons, s.trafficState) {
errors.LogDebug(s.ctx, "Scheduler Trigger for fake buffer with ", d, " ", trigger)
s.trafficState.NumberOfPacketSent += 1
mb := make(buf.MultiBuffer, 1)
mb[0] = XtlsPadding(nil, CommandPaddingContinue, s.writeOnceUserUUID, true, s.addons, s.ctx)
s.trafficState.ByteSent += int64(mb.Len())
if s.trafficState.StartTime.IsZero() {
s.trafficState.StartTime = time.Now()
}
err := s.writer.WriteMultiBuffer(mb)
if err != nil {
s.Error <- err
s.closed <- 1
return
}
if buffered, ok := s.writer.(*buf.BufferedWriter); ok {
buffered.SetBuffered(false)
}
}
s.bufferReadLock.Unlock()
}()
}
}
func(s *Scheduler) exampleIndependentScheduler() {
for {
if len(s.closed) > 0 {
return
}
s.Trigger <- 1 // send fake buffer if no pending
time.Sleep(500 * time.Millisecond)
}
}

View File

@@ -21,6 +21,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
XorMode: a.XorMode,
Seconds: a.Seconds,
Padding: a.Padding,
Seed: a.Seed,
}, nil
}
@@ -35,6 +36,8 @@ type MemoryAccount struct {
XorMode uint32
Seconds uint32
Padding string
// Seed. Details TBD
Seed string
}
// Equals implements protocol.Account.Equals().

View File

@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc-gen-go v1.36.8
// protoc v5.28.2
// source: proxy/vless/account.proto
@@ -11,6 +11,7 @@ import (
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
@@ -21,10 +22,7 @@ const (
)
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState `protogen:"open.v1"`
// 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".
@@ -33,6 +31,10 @@ type Account struct {
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"`
// Seed settings. Details TBD
Seed string `protobuf:"bytes,7,opt,name=seed,proto3" json:"seed,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Account) Reset() {
@@ -107,38 +109,38 @@ func (x *Account) GetPadding() string {
return ""
}
func (x *Account) GetSeed() string {
if x != nil {
return x.Seed
}
return ""
}
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,
}
const file_proxy_vless_account_proto_rawDesc = "" +
"\n" +
"\x19proxy/vless/account.proto\x12\x10xray.proxy.vless\"\xaf\x01\n" +
"\aAccount\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
"\x04flow\x18\x02 \x01(\tR\x04flow\x12\x1e\n" +
"\n" +
"encryption\x18\x03 \x01(\tR\n" +
"encryption\x12\x18\n" +
"\axorMode\x18\x04 \x01(\rR\axorMode\x12\x18\n" +
"\aseconds\x18\x05 \x01(\rR\aseconds\x12\x18\n" +
"\apadding\x18\x06 \x01(\tR\apadding\x12\x12\n" +
"\x04seed\x18\a \x01(\tR\x04seedBR\n" +
"\x14com.xray.proxy.vlessP\x01Z%github.com/xtls/xray-core/proxy/vless\xaa\x02\x10Xray.Proxy.Vlessb\x06proto3"
var (
file_proxy_vless_account_proto_rawDescOnce sync.Once
file_proxy_vless_account_proto_rawDescData = file_proxy_vless_account_proto_rawDesc
file_proxy_vless_account_proto_rawDescData []byte
)
func file_proxy_vless_account_proto_rawDescGZIP() []byte {
file_proxy_vless_account_proto_rawDescOnce.Do(func() {
file_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_account_proto_rawDescData)
file_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proxy_vless_account_proto_rawDesc), len(file_proxy_vless_account_proto_rawDesc)))
})
return file_proxy_vless_account_proto_rawDescData
}
@@ -164,7 +166,7 @@ func file_proxy_vless_account_proto_init() {
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_account_proto_rawDesc,
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_vless_account_proto_rawDesc), len(file_proxy_vless_account_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
@@ -175,7 +177,6 @@ func file_proxy_vless_account_proto_init() {
MessageInfos: file_proxy_vless_account_proto_msgTypes,
}.Build()
File_proxy_vless_account_proto = out.File
file_proxy_vless_account_proto_rawDesc = nil
file_proxy_vless_account_proto_goTypes = nil
file_proxy_vless_account_proto_depIdxs = nil
}

View File

@@ -16,4 +16,6 @@ message Account {
uint32 xorMode = 4;
uint32 seconds = 5;
string padding = 6;
// Seed settings. Details TBD
string seed = 7;
}

View File

@@ -1,6 +1,7 @@
package encoding
import (
"bytes"
"context"
"io"
"net"
@@ -14,9 +15,8 @@ import (
"google.golang.org/protobuf/proto"
)
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
switch addons.Flow {
case vless.XRV:
func EncodeHeaderAddons(buffer *buf.Buffer, addons *proxy.Addons) error {
if addons.Flow == vless.XRV || len(addons.Seed) > 0 {
bytes, err := proto.Marshal(addons)
if err != nil {
return errors.New("failed to marshal addons protobuf value").Base(err)
@@ -27,17 +27,16 @@ func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
if _, err := buffer.Write(bytes); err != nil {
return errors.New("failed to write addons protobuf value").Base(err)
}
default:
} else {
if err := buffer.WriteByte(0); err != nil {
return errors.New("failed to write addons protobuf length").Base(err)
}
}
return nil
}
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
addons := new(Addons)
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*proxy.Addons, error) {
addons := new(proxy.Addons)
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, errors.New("failed to read addons protobuf length").Base(err)
@@ -52,36 +51,27 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
return nil, errors.New("failed to unmarshal addons protobuf value").Base(err)
}
// Verification.
switch addons.Flow {
default:
}
}
return addons, nil
}
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer buf.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, ob *session.Outbound) buf.Writer {
func EncodeBodyAddons(writer buf.Writer, request *protocol.RequestHeader, addons *proxy.Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, ob *session.Outbound) buf.Writer {
w := proxy.NewVisionWriter(writer, addons, state, isUplink, context, conn, ob)
if request.Command == protocol.RequestCommandUDP {
return NewMultiLengthPacketWriter(writer)
}
if requestAddons.Flow == vless.XRV {
return proxy.NewVisionWriter(writer, state, isUplink, context, conn, ob)
return NewMultiLengthPacketWriter(w)
}
return writer
}
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {
switch addons.Flow {
default:
if request.Command == protocol.RequestCommandUDP {
return NewLengthPacketReader(reader)
}
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *proxy.Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) buf.Reader {
r := proxy.NewVisionReader(buf.NewReader(reader), addons, state, isUplink, context, conn, input, rawInput, ob)
if request.Command == protocol.RequestCommandUDP {
return NewLengthPacketReader(&buf.BufferedReader{Reader: r})
}
return buf.NewReader(reader)
return r
}
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
@@ -189,3 +179,78 @@ func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
}
return mb, nil
}
func PopulateSeed(seed string, addons *proxy.Addons) {
if len(seed) > 0 {
addons.Seed = []byte {1} // only turn on, more TBD
addons.Mode = proxy.SeedMode_PaddingPlusDelay
addons.Duration = "0-8"
addons.Padding = &proxy.PaddingConfig{
RegularMin: 0,
RegularMax: 256,
LongMin: 900,
LongMax: 1400,
}
// addons.Delay = &proxy.DelayConfig{
// IsRandom: true,
// MinMillis: 100,
// MaxMillis: 500,
// }
addons.Scheduler = &proxy.SchedulerConfig{
TimeoutMillis: 600,
}
} else if addons.Flow == vless.XRV {
addons.Seed = []byte {1} // only turn on, more TBD
addons.Mode = proxy.SeedMode_PaddingOnly
addons.Duration = "0-8"
addons.Padding = &proxy.PaddingConfig{
RegularMin: 0,
RegularMax: 256,
LongMin: 900,
LongMax: 1400,
}
}
}
func CheckSeed(requestAddons *proxy.Addons, responseAddons *proxy.Addons) error {
if !bytes.Equal(requestAddons.Seed, responseAddons.Seed) {
return errors.New("Seed bytes not match", requestAddons.Seed, responseAddons.Seed)
}
if responseAddons.Flow == vless.XRV && len(responseAddons.Seed) == 0 && requestAddons.Mode == proxy.SeedMode_Unknown {
// old vision server config allow empty seed from clients for backwards compatibility
return nil
}
if requestAddons.Mode != responseAddons.Mode {
return errors.New("Mode not match", requestAddons.Mode, responseAddons.Mode)
}
if requestAddons.Duration != responseAddons.Duration {
return errors.New("Duration not match", requestAddons.Duration, responseAddons.Duration)
}
if requestAddons.Padding != nil && responseAddons.Padding != nil {
if requestAddons.Padding.RegularMin != responseAddons.Padding.RegularMin ||
requestAddons.Padding.RegularMax != responseAddons.Padding.RegularMax ||
requestAddons.Padding.LongMin != responseAddons.Padding.LongMin ||
requestAddons.Padding.LongMax != responseAddons.Padding.LongMax {
return errors.New("Padding not match")
}
} else if requestAddons.Padding != nil || responseAddons.Padding != nil {
return errors.New("Padding of one is nil but the other is not nil")
}
if requestAddons.Delay != nil && responseAddons.Delay != nil {
if requestAddons.Delay.IsRandom != responseAddons.Delay.IsRandom ||
requestAddons.Delay.MinMillis != responseAddons.Delay.MinMillis ||
requestAddons.Delay.MaxMillis != responseAddons.Delay.MaxMillis {
return errors.New("Delay not match")
}
} else if requestAddons.Delay != nil || responseAddons.Delay != nil {
return errors.New("Delay of one is nil but the other is not nil")
}
if requestAddons.Scheduler != nil && responseAddons.Scheduler != nil {
if requestAddons.Scheduler.TimeoutMillis != responseAddons.Scheduler.TimeoutMillis {
return errors.New("Scheduler not match")
}
} else if requestAddons.Scheduler != nil || responseAddons.Scheduler != nil {
return errors.New("Scheduler of one is nil but the other is not nil")
}
return nil
}

View File

@@ -20,13 +20,70 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SeedMode int32
const (
SeedMode_Unknown SeedMode = 0
SeedMode_PaddingOnly SeedMode = 1
SeedMode_PaddingPlusDelay SeedMode = 2
SeedMode_IndependentScheduler SeedMode = 3
)
// Enum value maps for SeedMode.
var (
SeedMode_name = map[int32]string{
0: "Unknown",
1: "PaddingOnly",
2: "PaddingPlusDelay",
3: "IndependentScheduler",
}
SeedMode_value = map[string]int32{
"Unknown": 0,
"PaddingOnly": 1,
"PaddingPlusDelay": 2,
"IndependentScheduler": 3,
}
)
func (x SeedMode) Enum() *SeedMode {
p := new(SeedMode)
*p = x
return p
}
func (x SeedMode) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (SeedMode) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_vless_encoding_addons_proto_enumTypes[0].Descriptor()
}
func (SeedMode) Type() protoreflect.EnumType {
return &file_proxy_vless_encoding_addons_proto_enumTypes[0]
}
func (x SeedMode) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use SeedMode.Descriptor instead.
func (SeedMode) EnumDescriptor() ([]byte, []int) {
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{0}
}
type Addons struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
Mode SeedMode `protobuf:"varint,3,opt,name=Mode,proto3,enum=xray.proxy.vless.encoding.SeedMode" json:"Mode,omitempty"`
Duration string `protobuf:"bytes,4,opt,name=Duration,proto3" json:"Duration,omitempty"` // "0-8" means apply to number of packets, "1kb-" means start applying once both side exchange 1kb data, counting two-ways
Padding *PaddingConfig `protobuf:"bytes,5,opt,name=Padding,proto3" json:"Padding,omitempty"`
Delay *DelayConfig `protobuf:"bytes,6,opt,name=Delay,proto3" json:"Delay,omitempty"`
Scheduler *SchedulerConfig `protobuf:"bytes,7,opt,name=Scheduler,proto3" json:"Scheduler,omitempty"`
}
func (x *Addons) Reset() {
@@ -73,24 +130,282 @@ func (x *Addons) GetSeed() []byte {
return nil
}
func (x *Addons) GetMode() SeedMode {
if x != nil {
return x.Mode
}
return SeedMode_Unknown
}
func (x *Addons) GetDuration() string {
if x != nil {
return x.Duration
}
return ""
}
func (x *Addons) GetPadding() *PaddingConfig {
if x != nil {
return x.Padding
}
return nil
}
func (x *Addons) GetDelay() *DelayConfig {
if x != nil {
return x.Delay
}
return nil
}
func (x *Addons) GetScheduler() *SchedulerConfig {
if x != nil {
return x.Scheduler
}
return nil
}
type PaddingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RegularMin uint32 `protobuf:"varint,1,opt,name=RegularMin,proto3" json:"RegularMin,omitempty"`
RegularMax uint32 `protobuf:"varint,2,opt,name=RegularMax,proto3" json:"RegularMax,omitempty"`
LongMin uint32 `protobuf:"varint,3,opt,name=LongMin,proto3" json:"LongMin,omitempty"`
LongMax uint32 `protobuf:"varint,4,opt,name=LongMax,proto3" json:"LongMax,omitempty"`
}
func (x *PaddingConfig) Reset() {
*x = PaddingConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PaddingConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PaddingConfig) ProtoMessage() {}
func (x *PaddingConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PaddingConfig.ProtoReflect.Descriptor instead.
func (*PaddingConfig) Descriptor() ([]byte, []int) {
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{1}
}
func (x *PaddingConfig) GetRegularMin() uint32 {
if x != nil {
return x.RegularMin
}
return 0
}
func (x *PaddingConfig) GetRegularMax() uint32 {
if x != nil {
return x.RegularMax
}
return 0
}
func (x *PaddingConfig) GetLongMin() uint32 {
if x != nil {
return x.LongMin
}
return 0
}
func (x *PaddingConfig) GetLongMax() uint32 {
if x != nil {
return x.LongMax
}
return 0
}
type DelayConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsRandom bool `protobuf:"varint,1,opt,name=IsRandom,proto3" json:"IsRandom,omitempty"`
MinMillis uint32 `protobuf:"varint,2,opt,name=MinMillis,proto3" json:"MinMillis,omitempty"`
MaxMillis uint32 `protobuf:"varint,3,opt,name=MaxMillis,proto3" json:"MaxMillis,omitempty"`
}
func (x *DelayConfig) Reset() {
*x = DelayConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DelayConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DelayConfig) ProtoMessage() {}
func (x *DelayConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DelayConfig.ProtoReflect.Descriptor instead.
func (*DelayConfig) Descriptor() ([]byte, []int) {
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{2}
}
func (x *DelayConfig) GetIsRandom() bool {
if x != nil {
return x.IsRandom
}
return false
}
func (x *DelayConfig) GetMinMillis() uint32 {
if x != nil {
return x.MinMillis
}
return 0
}
func (x *DelayConfig) GetMaxMillis() uint32 {
if x != nil {
return x.MaxMillis
}
return 0
}
type SchedulerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TimeoutMillis uint32 `protobuf:"varint,1,opt,name=TimeoutMillis,proto3" json:"TimeoutMillis,omitempty"` // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
}
func (x *SchedulerConfig) Reset() {
*x = SchedulerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SchedulerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SchedulerConfig) ProtoMessage() {}
func (x *SchedulerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SchedulerConfig.ProtoReflect.Descriptor instead.
func (*SchedulerConfig) Descriptor() ([]byte, []int) {
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{3}
}
func (x *SchedulerConfig) GetTimeoutMillis() uint32 {
if x != nil {
return x.TimeoutMillis
}
return 0
}
var File_proxy_vless_encoding_addons_proto protoreflect.FileDescriptor
var file_proxy_vless_encoding_addons_proto_rawDesc = []byte{
0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e,
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x30,
0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04,
0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65, 0x64,
0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
0x67, 0x50, 0x01, 0x5a, 0x2e, 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, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64,
0x69, 0x6e, 0x67, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xd1,
0x02, 0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f,
0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a,
0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65,
0x64, 0x12, 0x37, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65,
0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x65, 0x64,
0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x44, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e,
0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64,
0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3c, 0x0a, 0x05, 0x44, 0x65,
0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63,
0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x48, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65,
0x64, 0x75, 0x6c, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65,
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d,
0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
0x72, 0x4d, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d,
0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
0x72, 0x4d, 0x61, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x12, 0x18,
0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x22, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x61,
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x52, 0x61, 0x6e,
0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x52, 0x61, 0x6e,
0x64, 0x6f, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x69, 0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x69, 0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x22,
0x37, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c,
0x6c, 0x69, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x2a, 0x58, 0x0a, 0x08, 0x53, 0x65, 0x65, 0x64,
0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10,
0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79,
0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75,
0x73, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x6e, 0x64, 0x65,
0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
0x10, 0x03, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64,
0x69, 0x6e, 0x67, 0x50, 0x01, 0x5a, 0x2e, 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, 0x2f, 0x65, 0x6e, 0x63,
0x6f, 0x64, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -105,16 +420,25 @@ func file_proxy_vless_encoding_addons_proto_rawDescGZIP() []byte {
return file_proxy_vless_encoding_addons_proto_rawDescData
}
var file_proxy_vless_encoding_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_vless_encoding_addons_proto_goTypes = []any{
(*Addons)(nil), // 0: xray.proxy.vless.encoding.Addons
var file_proxy_vless_encoding_addons_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proxy_vless_encoding_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_vless_encoding_addons_proto_goTypes = []interface{}{
(SeedMode)(0), // 0: xray.proxy.vless.encoding.SeedMode
(*Addons)(nil), // 1: xray.proxy.vless.encoding.Addons
(*PaddingConfig)(nil), // 2: xray.proxy.vless.encoding.PaddingConfig
(*DelayConfig)(nil), // 3: xray.proxy.vless.encoding.DelayConfig
(*SchedulerConfig)(nil), // 4: xray.proxy.vless.encoding.SchedulerConfig
}
var file_proxy_vless_encoding_addons_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.encoding.Addons.Mode:type_name -> xray.proxy.vless.encoding.SeedMode
2, // 1: xray.proxy.vless.encoding.Addons.Padding:type_name -> xray.proxy.vless.encoding.PaddingConfig
3, // 2: xray.proxy.vless.encoding.Addons.Delay:type_name -> xray.proxy.vless.encoding.DelayConfig
4, // 3: xray.proxy.vless.encoding.Addons.Scheduler:type_name -> xray.proxy.vless.encoding.SchedulerConfig
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proxy_vless_encoding_addons_proto_init() }
@@ -122,18 +446,69 @@ func file_proxy_vless_encoding_addons_proto_init() {
if File_proxy_vless_encoding_addons_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vless_encoding_addons_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*Addons); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vless_encoding_addons_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PaddingConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vless_encoding_addons_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DelayConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vless_encoding_addons_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_encoding_addons_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vless_encoding_addons_proto_goTypes,
DependencyIndexes: file_proxy_vless_encoding_addons_proto_depIdxs,
EnumInfos: file_proxy_vless_encoding_addons_proto_enumTypes,
MessageInfos: file_proxy_vless_encoding_addons_proto_msgTypes,
}.Build()
File_proxy_vless_encoding_addons_proto = out.File

View File

@@ -1,12 +0,0 @@
syntax = "proto3";
package xray.proxy.vless.encoding;
option csharp_namespace = "Xray.Proxy.Vless.Encoding";
option go_package = "github.com/xtls/xray-core/proxy/vless/encoding";
option java_package = "com.xray.proxy.vless.encoding";
option java_multiple_files = true;
message Addons {
string Flow = 1;
bytes Seed = 2;
}

View File

@@ -26,7 +26,7 @@ var addrParser = protocol.NewAddressParser(
)
// EncodeRequestHeader writes encoded request header into the given writer.
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error {
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *proxy.Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
@@ -60,7 +60,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
}
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) ([]byte, *protocol.RequestHeader, *Addons, bool, error) {
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) ([]byte, *protocol.RequestHeader, *proxy.Addons, bool, error) {
buffer := buf.StackNew()
defer buffer.Release()
@@ -129,7 +129,7 @@ func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validat
}
// EncodeResponseHeader writes encoded response header into the given writer.
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error {
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *proxy.Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
@@ -149,7 +149,7 @@ func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, res
}
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*Addons, error) {
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*proxy.Addons, error) {
buffer := buf.StackNew()
defer buffer.Release()

View File

@@ -9,6 +9,7 @@ import (
"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"
"github.com/xtls/xray-core/proxy/vless"
. "github.com/xtls/xray-core/proxy/vless/encoding"
)
@@ -37,7 +38,7 @@ func TestRequestSerialization(t *testing.T) {
Address: net.DomainAddress("www.example.com"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
expectedAddons := &proxy.Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
@@ -52,7 +53,7 @@ func TestRequestSerialization(t *testing.T) {
t.Error(r)
}
addonsComparer := func(x, y *Addons) bool {
addonsComparer := func(x, y *proxy.Addons) bool {
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
}
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
@@ -78,7 +79,7 @@ func TestInvalidRequest(t *testing.T) {
Address: net.DomainAddress("www.example.com"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
expectedAddons := &proxy.Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
@@ -109,7 +110,7 @@ func TestMuxRequest(t *testing.T) {
Command: protocol.RequestCommandMux,
Address: net.DomainAddress("v1.mux.cool"),
}
expectedAddons := &Addons{}
expectedAddons := &proxy.Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
@@ -124,7 +125,7 @@ func TestMuxRequest(t *testing.T) {
t.Error(r)
}
addonsComparer := func(x, y *Addons) bool {
addonsComparer := func(x, y *proxy.Addons) bool {
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
}
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {

View File

@@ -246,7 +246,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
var userSentID []byte // not MemoryAccount.ID
var request *protocol.RequestHeader
var requestAddons *encoding.Addons
var requestAddons *proxy.Addons
var err error
napfb := h.fallbacks
@@ -487,8 +487,12 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
account := request.User.Account.(*vless.MemoryAccount)
responseAddons := &encoding.Addons{
// Flow: requestAddons.Flow,
responseAddons := &proxy.Addons{
Flow: account.Flow,
}
encoding.PopulateSeed(account.Seed, responseAddons)
if check := encoding.CheckSeed(requestAddons, responseAddons); check != nil {
return errors.New("Seed configuration mis-match").Base(check).AtWarning()
}
var input *bytes.Reader
@@ -552,17 +556,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
}
trafficState := proxy.NewTrafficState(userSentID)
clientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)
if requestAddons.Flow == vless.XRV {
clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx, connection, input, rawInput, nil)
}
trafficState := proxy.NewTrafficState(userSentID, account.Flow)
clientReader := encoding.DecodeBodyAddons(reader, request, responseAddons, trafficState, true, ctx, connection, input, rawInput, nil)
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
return errors.New("failed to encode response header").Base(err).AtWarning()
}
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons, trafficState, false, ctx, connection, nil)
bufferWriter.SetFlushNext()
if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{

View File

@@ -141,9 +141,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
account := request.User.Account.(*vless.MemoryAccount)
requestAddons := &encoding.Addons{
requestAddons := &proxy.Addons{
Flow: account.Flow,
}
encoding.PopulateSeed(account.Seed, requestAddons)
var input *bytes.Reader
var rawInput *bytes.Buffer
@@ -209,7 +210,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer)
trafficState := proxy.NewTrafficState(account.ID.Bytes())
trafficState := proxy.NewTrafficState(account.ID.Bytes(), account.Flow)
if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
@@ -285,16 +286,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
// default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
if requestAddons.Flow == vless.XRV {
serverReader = proxy.NewVisionReader(serverReader, trafficState, false, ctx, conn, input, rawInput, ob)
}
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons, trafficState, false, ctx, conn, input, rawInput, ob)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
if requestAddons.Flow == vless.XRV {
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
} else {
serverReader = xudp.NewPacketReader(conn)
}
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
}
if requestAddons.Flow == vless.XRV {

View File

@@ -125,6 +125,104 @@ func TestVless(t *testing.T) {
}
}
func TestVlessSeedWithIndependentScheduler(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(),
Seed: "1",
}),
},
},
}),
},
},
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{
{
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(),
Seed: "1",
}),
},
},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
}
if err := errg.Wait(); err != nil {
t.Error(err)
}
}
func TestVlessTls(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
@@ -371,6 +469,132 @@ func TestVlessXtlsVision(t *testing.T) {
}
}
func TestVlessXtlsVisionWithSeed(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),
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
Flow: vless.XRV,
Seed: "1",
}),
},
},
}),
},
},
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{
{
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(),
Flow: vless.XRV,
Seed: "1",
}),
},
},
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "tcp",
Settings: serial.ToTypedMessage(&transtcp.Config{}),
},
},
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
AllowInsecure: true,
}),
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
}
if err := errg.Wait(); err != nil {
t.Error(err)
}
}
func TestVlessXtlsVisionReality(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,