mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-14 05:04:12 +08:00
Merge f0e6bdf4ce331cf6940b19b0aa6811b1ce57258d into 72170d8b6be0d83af1624f6d31b81cf73f1a189c
This commit is contained in:
commit
00bcff2afa
@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
type dataHandler func(MultiBuffer)
|
type dataHandler func(MultiBuffer)
|
||||||
|
|
||||||
type copyHandler struct {
|
type CopyHandler struct {
|
||||||
onData []dataHandler
|
OnData []dataHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// SizeCounter is for counting bytes copied by Copy().
|
// SizeCounter is for counting bytes copied by Copy().
|
||||||
@ -21,12 +21,12 @@ type SizeCounter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyOption is an option for copying data.
|
// CopyOption is an option for copying data.
|
||||||
type CopyOption func(*copyHandler)
|
type CopyOption func(*CopyHandler)
|
||||||
|
|
||||||
// UpdateActivity is a CopyOption to update activity on each data copy operation.
|
// UpdateActivity is a CopyOption to update activity on each data copy operation.
|
||||||
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
|
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
|
||||||
return func(handler *copyHandler) {
|
return func(handler *CopyHandler) {
|
||||||
handler.onData = append(handler.onData, func(MultiBuffer) {
|
handler.OnData = append(handler.OnData, func(MultiBuffer) {
|
||||||
timer.Update()
|
timer.Update()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -34,8 +34,8 @@ func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
|
|||||||
|
|
||||||
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
|
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
|
||||||
func CountSize(sc *SizeCounter) CopyOption {
|
func CountSize(sc *SizeCounter) CopyOption {
|
||||||
return func(handler *copyHandler) {
|
return func(handler *CopyHandler) {
|
||||||
handler.onData = append(handler.onData, func(b MultiBuffer) {
|
handler.OnData = append(handler.OnData, func(b MultiBuffer) {
|
||||||
sc.Size += int64(b.Len())
|
sc.Size += int64(b.Len())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -43,8 +43,8 @@ func CountSize(sc *SizeCounter) CopyOption {
|
|||||||
|
|
||||||
// AddToStatCounter a CopyOption add to stat counter
|
// AddToStatCounter a CopyOption add to stat counter
|
||||||
func AddToStatCounter(sc stats.Counter) CopyOption {
|
func AddToStatCounter(sc stats.Counter) CopyOption {
|
||||||
return func(handler *copyHandler) {
|
return func(handler *CopyHandler) {
|
||||||
handler.onData = append(handler.onData, func(b MultiBuffer) {
|
handler.OnData = append(handler.OnData, func(b MultiBuffer) {
|
||||||
if sc != nil {
|
if sc != nil {
|
||||||
sc.Add(int64(b.Len()))
|
sc.Add(int64(b.Len()))
|
||||||
}
|
}
|
||||||
@ -88,18 +88,17 @@ func IsWriteError(err error) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
|
func copyInternal(reader Reader, writer Writer, handler *CopyHandler) error {
|
||||||
for {
|
for {
|
||||||
buffer, err := reader.ReadMultiBuffer()
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
if !buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
for _, handler := range handler.onData {
|
|
||||||
handler(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
return writeError{werr}
|
return writeError{werr}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, handler := range handler.OnData {
|
||||||
|
handler(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return readError{err}
|
return readError{err}
|
||||||
@ -109,7 +108,7 @@ func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
|
|||||||
|
|
||||||
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
|
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
|
||||||
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
|
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
|
||||||
var handler copyHandler
|
var handler CopyHandler
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(&handler)
|
option(&handler)
|
||||||
}
|
}
|
||||||
|
521
proxy/addons.pb.go
Normal file
521
proxy/addons.pb.go
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc v5.27.0
|
||||||
|
// 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
|
||||||
|
PingPong bool `protobuf:"varint,2,opt,name=PingPong,proto3" json:"PingPong,omitempty"` // Other TBD
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SchedulerConfig) GetPingPong() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.PingPong
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 0x53, 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, 0x12, 0x1a,
|
||||||
|
0x0a, 0x08, 0x50, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
|
||||||
|
0x52, 0x08, 0x50, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6e, 0x67, 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 = []any{
|
||||||
|
(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 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_addons_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
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 any, i int) any {
|
||||||
|
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 any, i int) any {
|
||||||
|
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
|
||||||
|
}
|
43
proxy/addons.proto
Normal file
43
proxy/addons.proto
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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
|
||||||
|
bool PingPong = 2;
|
||||||
|
// Other TBD
|
||||||
|
}
|
@ -231,7 +231,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
inTimer = inbound.Timer
|
inTimer = inbound.Timer
|
||||||
}
|
}
|
||||||
if !isTLSConn(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
if !isTLSConn(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
||||||
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer)
|
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var reader buf.Reader
|
var reader buf.Reader
|
||||||
|
165
proxy/proxy.go
165
proxy/proxy.go
@ -13,6 +13,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pires/go-proxyproto"
|
"github.com/pires/go-proxyproto"
|
||||||
@ -101,6 +102,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
|
// It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
|
||||||
type TrafficState struct {
|
type TrafficState struct {
|
||||||
UserUUID []byte
|
UserUUID []byte
|
||||||
|
StartTime time.Time
|
||||||
|
ByteSent int64
|
||||||
|
ByteReceived int64
|
||||||
|
NumberOfPacketSent int
|
||||||
|
NumberOfPacketReceived int
|
||||||
NumberOfPacketToFilter int
|
NumberOfPacketToFilter int
|
||||||
EnableXtls bool
|
EnableXtls bool
|
||||||
IsTLS12orAbove bool
|
IsTLS12orAbove bool
|
||||||
@ -137,9 +143,14 @@ type OutboundState struct {
|
|||||||
UplinkWriterDirectCopy bool
|
UplinkWriterDirectCopy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrafficState(userUUID []byte) *TrafficState {
|
func NewTrafficState(userUUID []byte, flow string) *TrafficState {
|
||||||
return &TrafficState{
|
var state = TrafficState{
|
||||||
UserUUID: userUUID,
|
UserUUID: userUUID,
|
||||||
|
StartTime: time.Time{},
|
||||||
|
ByteSent: 0,
|
||||||
|
ByteReceived: 0,
|
||||||
|
NumberOfPacketSent: 0,
|
||||||
|
NumberOfPacketReceived: 0,
|
||||||
NumberOfPacketToFilter: 8,
|
NumberOfPacketToFilter: 8,
|
||||||
EnableXtls: false,
|
EnableXtls: false,
|
||||||
IsTLS12orAbove: false,
|
IsTLS12orAbove: false,
|
||||||
@ -147,40 +158,45 @@ func NewTrafficState(userUUID []byte) *TrafficState {
|
|||||||
Cipher: 0,
|
Cipher: 0,
|
||||||
RemainingServerHello: -1,
|
RemainingServerHello: -1,
|
||||||
Inbound: InboundState{
|
Inbound: InboundState{
|
||||||
WithinPaddingBuffers: true,
|
|
||||||
UplinkReaderDirectCopy: false,
|
UplinkReaderDirectCopy: false,
|
||||||
RemainingCommand: -1,
|
RemainingCommand: -1,
|
||||||
RemainingContent: -1,
|
RemainingContent: -1,
|
||||||
RemainingPadding: -1,
|
RemainingPadding: -1,
|
||||||
CurrentCommand: 0,
|
CurrentCommand: 0,
|
||||||
IsPadding: true,
|
|
||||||
DownlinkWriterDirectCopy: false,
|
DownlinkWriterDirectCopy: false,
|
||||||
|
IsPadding: true,
|
||||||
},
|
},
|
||||||
Outbound: OutboundState{
|
Outbound: OutboundState{
|
||||||
WithinPaddingBuffers: true,
|
|
||||||
DownlinkReaderDirectCopy: false,
|
DownlinkReaderDirectCopy: false,
|
||||||
RemainingCommand: -1,
|
RemainingCommand: -1,
|
||||||
RemainingContent: -1,
|
RemainingContent: -1,
|
||||||
RemainingPadding: -1,
|
RemainingPadding: -1,
|
||||||
CurrentCommand: 0,
|
CurrentCommand: 0,
|
||||||
IsPadding: true,
|
|
||||||
UplinkWriterDirectCopy: false,
|
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
|
// 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 {
|
type VisionReader struct {
|
||||||
buf.Reader
|
buf.Reader
|
||||||
|
addons *Addons
|
||||||
trafficState *TrafficState
|
trafficState *TrafficState
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
isUplink bool
|
isUplink bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
|
func NewVisionReader(reader buf.Reader, addon *Addons, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
|
||||||
return &VisionReader{
|
return &VisionReader{
|
||||||
Reader: reader,
|
Reader: reader,
|
||||||
|
addons: addon,
|
||||||
trafficState: state,
|
trafficState: state,
|
||||||
ctx: context,
|
ctx: context,
|
||||||
isUplink: isUplink,
|
isUplink: isUplink,
|
||||||
@ -190,6 +206,10 @@ func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, cont
|
|||||||
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
buffer, err := w.Reader.ReadMultiBuffer()
|
buffer, err := w.Reader.ReadMultiBuffer()
|
||||||
if !buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
|
if w.trafficState.StartTime.IsZero() {
|
||||||
|
w.trafficState.StartTime = time.Now()
|
||||||
|
}
|
||||||
|
w.trafficState.ByteReceived += int64(buffer.Len())
|
||||||
var withinPaddingBuffers *bool
|
var withinPaddingBuffers *bool
|
||||||
var remainingContent *int32
|
var remainingContent *int32
|
||||||
var remainingPadding *int32
|
var remainingPadding *int32
|
||||||
@ -209,7 +229,7 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
|
if *withinPaddingBuffers || w.trafficState.NumberOfPacketReceived <= 8 || !ShouldStopSeed(w.addons, w.trafficState) {
|
||||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||||
for _, b := range buffer {
|
for _, b := range buffer {
|
||||||
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
||||||
@ -229,6 +249,7 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
w.trafficState.NumberOfPacketReceived += len(buffer)
|
||||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||||
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
||||||
}
|
}
|
||||||
@ -236,29 +257,34 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
return buffer, err
|
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
|
// 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 {
|
type VisionWriter struct {
|
||||||
buf.Writer
|
buf.Writer
|
||||||
|
addons *Addons
|
||||||
trafficState *TrafficState
|
trafficState *TrafficState
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
writeOnceUserUUID []byte
|
writeOnceUserUUID *[]byte
|
||||||
isUplink bool
|
isUplink bool
|
||||||
|
Scheduler *Scheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
|
func NewVisionWriter(writer buf.Writer, addon *Addons, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
|
||||||
w := make([]byte, len(state.UserUUID))
|
w := make([]byte, len(state.UserUUID))
|
||||||
copy(w, state.UserUUID)
|
copy(w, state.UserUUID)
|
||||||
return &VisionWriter{
|
return &VisionWriter{
|
||||||
Writer: writer,
|
Writer: writer,
|
||||||
|
addons: addon,
|
||||||
trafficState: state,
|
trafficState: state,
|
||||||
ctx: context,
|
ctx: context,
|
||||||
writeOnceUserUUID: w,
|
writeOnceUserUUID: &w,
|
||||||
isUplink: isUplink,
|
isUplink: isUplink,
|
||||||
|
Scheduler: NewScheduler(writer, addon, state, &w, context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
|
w.trafficState.NumberOfPacketSent += len(mb)
|
||||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||||
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
||||||
}
|
}
|
||||||
@ -271,11 +297,10 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
isPadding = &w.trafficState.Inbound.IsPadding
|
isPadding = &w.trafficState.Inbound.IsPadding
|
||||||
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
|
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
|
||||||
}
|
}
|
||||||
if *isPadding {
|
if *isPadding && ShouldStartSeed(w.addons, w.trafficState) {
|
||||||
if len(mb) == 1 && mb[0] == nil {
|
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
|
mb[0] = XtlsPadding(nil, CommandPaddingContinue, w.writeOnceUserUUID, true, w.addons, w.ctx) // we do a long padding to hide vless header
|
||||||
return w.Writer.WriteMultiBuffer(mb)
|
} else {
|
||||||
}
|
|
||||||
mb = ReshapeMultiBuffer(w.ctx, mb)
|
mb = ReshapeMultiBuffer(w.ctx, mb)
|
||||||
longPadding := w.trafficState.IsTLS
|
longPadding := w.trafficState.IsTLS
|
||||||
for i, b := range mb {
|
for i, b := range mb {
|
||||||
@ -285,18 +310,20 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
var command byte = CommandPaddingContinue
|
var command byte = CommandPaddingContinue
|
||||||
if i == len(mb) - 1 {
|
if i == len(mb) - 1 {
|
||||||
command = CommandPaddingEnd
|
|
||||||
if w.trafficState.EnableXtls {
|
if w.trafficState.EnableXtls {
|
||||||
command = CommandPaddingDirect
|
command = CommandPaddingDirect
|
||||||
|
*isPadding = false
|
||||||
|
} else if ShouldStopSeed(w.addons, w.trafficState) {
|
||||||
|
command = CommandPaddingEnd
|
||||||
|
*isPadding = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
|
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, true, w.addons, w.ctx)
|
||||||
*isPadding = false // padding going to end
|
|
||||||
longPadding = false
|
longPadding = false
|
||||||
continue
|
continue
|
||||||
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
|
} else if !w.trafficState.IsTLS12orAbove && ShouldStopSeed(w.addons, w.trafficState) {
|
||||||
*isPadding = false
|
*isPadding = false
|
||||||
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
|
mb[i] = XtlsPadding(b, CommandPaddingEnd, w.writeOnceUserUUID, longPadding, w.addons, w.ctx)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var command byte = CommandPaddingContinue
|
var command byte = CommandPaddingContinue
|
||||||
@ -306,10 +333,34 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
command = CommandPaddingDirect
|
command = CommandPaddingDirect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
|
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, longPadding, w.addons, 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
|
||||||
|
w.Scheduler.Trigger <- -1 // send all buffers if no independent scheduler
|
||||||
|
if w.addons.Scheduler != nil {
|
||||||
|
w.Scheduler.TimeoutLock.Lock()
|
||||||
|
w.Scheduler.TimeoutCounter++
|
||||||
|
w.Scheduler.TimeoutLock.Unlock()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Duration(w.addons.Scheduler.TimeoutMillis) * time.Millisecond)
|
||||||
|
w.Scheduler.TimeoutLock.Lock()
|
||||||
|
w.Scheduler.TimeoutCounter--
|
||||||
|
if w.Scheduler.TimeoutCounter == 0 {
|
||||||
|
w.Scheduler.Trigger <- 0 // send when the latest buffer timeout
|
||||||
|
}
|
||||||
|
w.Scheduler.TimeoutLock.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if len(w.Scheduler.Error) > 0 {
|
||||||
|
return <-w.Scheduler.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
|
// ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
|
||||||
@ -348,24 +399,24 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XtlsPadding add padding to eliminate length signature during tls handshake
|
// 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 contentLen int32 = 0
|
||||||
var paddingLen int32 = 0
|
var paddingLen int32 = 0
|
||||||
if b != nil {
|
if b != nil {
|
||||||
contentLen = b.Len()
|
contentLen = b.Len()
|
||||||
}
|
}
|
||||||
if contentLen < 900 && longPadding {
|
if contentLen < int32(addons.Padding.LongMin) && longPadding {
|
||||||
l, err := rand.Int(rand.Reader, big.NewInt(500))
|
l, err := rand.Int(rand.Reader, big.NewInt(int64(addons.Padding.LongMax - addons.Padding.LongMin)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
||||||
}
|
}
|
||||||
paddingLen = int32(l.Int64()) + 900 - contentLen
|
paddingLen = int32(l.Int64()) + int32(addons.Padding.LongMin) - contentLen
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
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 {
|
if paddingLen > buf.Size-21-contentLen {
|
||||||
paddingLen = buf.Size - 21 - contentLen
|
paddingLen = buf.Size - 21 - contentLen
|
||||||
@ -557,7 +608,7 @@ func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
|
|||||||
// CopyRawConnIfExist use the most efficient copy method.
|
// CopyRawConnIfExist use the most efficient copy method.
|
||||||
// - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
|
// - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
|
||||||
// - writer are from *transport.Link
|
// - writer are from *transport.Link
|
||||||
func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer *signal.ActivityTimer, inTimer *signal.ActivityTimer) error {
|
func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer *signal.ActivityTimer, inTimer *signal.ActivityTimer, scheduler *Scheduler) error {
|
||||||
readerConn, readCounter, _ := UnwrapRawConn(readerConn)
|
readerConn, readCounter, _ := UnwrapRawConn(readerConn)
|
||||||
writerConn, _, writeCounter := UnwrapRawConn(writerConn)
|
writerConn, _, writeCounter := UnwrapRawConn(writerConn)
|
||||||
reader := buf.NewReader(readerConn)
|
reader := buf.NewReader(readerConn)
|
||||||
@ -620,10 +671,13 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
|
|||||||
if readCounter != nil {
|
if readCounter != nil {
|
||||||
readCounter.Add(int64(buffer.Len()))
|
readCounter.Add(int64(buffer.Len()))
|
||||||
}
|
}
|
||||||
timer.Update()
|
|
||||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
return werr
|
return werr
|
||||||
}
|
}
|
||||||
|
timer.Update()
|
||||||
|
}
|
||||||
|
if scheduler != nil {
|
||||||
|
scheduler.Trigger <- 2
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -638,3 +692,50 @@ func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer sign
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
128
proxy/scheduler.go
Normal file
128
proxy/scheduler.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
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
|
||||||
|
TimeoutCounter int
|
||||||
|
TimeoutLock *sync.Mutex
|
||||||
|
closed chan int
|
||||||
|
bufferReadLock *sync.Mutex
|
||||||
|
writer buf.Writer
|
||||||
|
addons *Addons
|
||||||
|
trafficState *TrafficState
|
||||||
|
writeOnceUserUUID *[]byte
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func TriggerScheduler(scheduler *Scheduler) buf.CopyOption {
|
||||||
|
return func(handler *buf.CopyHandler) {
|
||||||
|
handler.OnData = append(handler.OnData, func(buf.MultiBuffer) {
|
||||||
|
scheduler.Trigger <- 2 // send fake buffer if no pending
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
TimeoutCounter: 0,
|
||||||
|
TimeoutLock: new(sync.Mutex),
|
||||||
|
closed: make(chan int),
|
||||||
|
bufferReadLock: new(sync.Mutex),
|
||||||
|
writer: w,
|
||||||
|
addons: addon,
|
||||||
|
trafficState: state,
|
||||||
|
writeOnceUserUUID: userUUID,
|
||||||
|
ctx: context,
|
||||||
|
}
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
func(s *Scheduler) Start() {
|
||||||
|
go s.mainLoop()
|
||||||
|
if s.addons.Scheduler != nil && !s.addons.Scheduler.PingPong {
|
||||||
|
go s.exampleIndependentScheduler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func(s *Scheduler) mainLoop() {
|
||||||
|
for trigger := range s.Trigger {
|
||||||
|
if len(s.closed) > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if trigger == -1 && s.addons.Scheduler != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if trigger == 2 && (s.addons.Scheduler == nil || !s.addons.Scheduler.PingPong) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
|||||||
ID: protocol.NewID(id),
|
ID: protocol.NewID(id),
|
||||||
Flow: a.Flow, // needs parser here?
|
Flow: a.Flow, // needs parser here?
|
||||||
Encryption: a.Encryption, // needs parser here?
|
Encryption: a.Encryption, // needs parser here?
|
||||||
|
Seed: a.Seed,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +30,8 @@ type MemoryAccount struct {
|
|||||||
Flow string
|
Flow string
|
||||||
// Encryption of the account. Used for client connections, and only accepts "none" for now.
|
// Encryption of the account. Used for client connections, and only accepts "none" for now.
|
||||||
Encryption string
|
Encryption string
|
||||||
|
// Seed. Details TBD
|
||||||
|
Seed string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals implements protocol.Account.Equals().
|
// Equals implements protocol.Account.Equals().
|
||||||
|
@ -31,6 +31,8 @@ type Account struct {
|
|||||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||||
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
||||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||||
|
// Seed settings. Details TBD
|
||||||
|
Seed string `protobuf:"bytes,4,opt,name=seed,proto3" json:"seed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Account) Reset() {
|
func (x *Account) Reset() {
|
||||||
@ -84,23 +86,31 @@ func (x *Account) GetEncryption() string {
|
|||||||
return ""
|
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 protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_vless_account_proto_rawDesc = []byte{
|
var file_proxy_vless_account_proto_rawDesc = []byte{
|
||||||
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
|
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,
|
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, 0x4d, 0x0a,
|
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x61, 0x0a,
|
||||||
0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
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,
|
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,
|
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,
|
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, 0x42, 0x52, 0x0a, 0x14,
|
0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
|
0x73, 0x65, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64,
|
||||||
0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68,
|
||||||
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x10,
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73,
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73,
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
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 (
|
var (
|
||||||
|
@ -13,4 +13,6 @@ message Account {
|
|||||||
string flow = 2;
|
string flow = 2;
|
||||||
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
||||||
string encryption = 3;
|
string encryption = 3;
|
||||||
|
// Seed settings. Details TBD
|
||||||
|
string seed = 4;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package encoding
|
package encoding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@ -12,9 +14,8 @@ import (
|
|||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
func EncodeHeaderAddons(buffer *buf.Buffer, addons *proxy.Addons) error {
|
||||||
switch addons.Flow {
|
if addons.Flow == vless.XRV || len(addons.Seed) > 0 {
|
||||||
case vless.XRV:
|
|
||||||
bytes, err := proto.Marshal(addons)
|
bytes, err := proto.Marshal(addons)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to marshal addons protobuf value").Base(err)
|
return errors.New("failed to marshal addons protobuf value").Base(err)
|
||||||
@ -25,17 +26,16 @@ func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
|||||||
if _, err := buffer.Write(bytes); err != nil {
|
if _, err := buffer.Write(bytes); err != nil {
|
||||||
return errors.New("failed to write addons protobuf value").Base(err)
|
return errors.New("failed to write addons protobuf value").Base(err)
|
||||||
}
|
}
|
||||||
default:
|
} else {
|
||||||
if err := buffer.WriteByte(0); err != nil {
|
if err := buffer.WriteByte(0); err != nil {
|
||||||
return errors.New("failed to write addons protobuf length").Base(err)
|
return errors.New("failed to write addons protobuf length").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
|
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*proxy.Addons, error) {
|
||||||
addons := new(Addons)
|
addons := new(proxy.Addons)
|
||||||
buffer.Clear()
|
buffer.Clear()
|
||||||
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
|
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
|
||||||
return nil, errors.New("failed to read addons protobuf length").Base(err)
|
return nil, errors.New("failed to read addons protobuf length").Base(err)
|
||||||
@ -50,37 +50,18 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
|
|||||||
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
|
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
|
||||||
return nil, errors.New("failed to unmarshal addons protobuf value").Base(err)
|
return nil, errors.New("failed to unmarshal addons protobuf value").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verification.
|
|
||||||
switch addons.Flow {
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addons, nil
|
return addons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
|
|
||||||
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context) buf.Writer {
|
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
|
||||||
return NewMultiLengthPacketWriter(writer.(buf.Writer))
|
|
||||||
}
|
|
||||||
w := buf.NewWriter(writer)
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
|
||||||
w = proxy.NewVisionWriter(w, state, isUplink, context)
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
||||||
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {
|
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *proxy.Addons, state *proxy.TrafficState, isUplink bool, context context.Context) buf.Reader {
|
||||||
switch addons.Flow {
|
r := proxy.NewVisionReader(buf.NewReader(reader), addons, state, isUplink, context)
|
||||||
default:
|
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
return NewLengthPacketReader(reader)
|
return NewLengthPacketReader(&buf.BufferedReader{Reader: r})
|
||||||
}
|
}
|
||||||
}
|
return r
|
||||||
return buf.NewReader(reader)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
|
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
|
||||||
@ -188,3 +169,80 @@ func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
return mb, nil
|
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_IndependentScheduler
|
||||||
|
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,
|
||||||
|
PingPong: strings.Contains(seed, "pingpong"),
|
||||||
|
}
|
||||||
|
} 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 ||
|
||||||
|
requestAddons.Scheduler.PingPong != responseAddons.Scheduler.PingPong {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
@ -20,6 +20,58 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = 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 {
|
type Addons struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -27,6 +79,11 @@ type Addons struct {
|
|||||||
|
|
||||||
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,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"`
|
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() {
|
func (x *Addons) Reset() {
|
||||||
@ -73,24 +130,282 @@ func (x *Addons) GetSeed() []byte {
|
|||||||
return nil
|
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 protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_vless_encoding_addons_proto_rawDesc = []byte{
|
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,
|
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,
|
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,
|
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,
|
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xd1,
|
||||||
0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77,
|
0x02, 0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04,
|
0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a,
|
||||||
0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65, 0x64,
|
0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65,
|
||||||
0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
0x64, 0x12, 0x37, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||||
0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
|
0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65,
|
||||||
0x67, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x65, 0x64,
|
||||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
|
0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x75,
|
||||||
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64,
|
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x44, 0x75,
|
||||||
0x69, 0x6e, 0x67, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e,
|
||||||
0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x62,
|
0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
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 (
|
var (
|
||||||
@ -105,16 +420,25 @@ func file_proxy_vless_encoding_addons_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_vless_encoding_addons_proto_rawDescData
|
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_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_proxy_vless_encoding_addons_proto_goTypes = []any{
|
var file_proxy_vless_encoding_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
(*Addons)(nil), // 0: xray.proxy.vless.encoding.Addons
|
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{
|
var file_proxy_vless_encoding_addons_proto_depIdxs = []int32{
|
||||||
0, // [0:0] is the sub-list for method output_type
|
0, // 0: xray.proxy.vless.encoding.Addons.Mode:type_name -> xray.proxy.vless.encoding.SeedMode
|
||||||
0, // [0:0] is the sub-list for method input_type
|
2, // 1: xray.proxy.vless.encoding.Addons.Padding:type_name -> xray.proxy.vless.encoding.PaddingConfig
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
3, // 2: xray.proxy.vless.encoding.Addons.Delay:type_name -> xray.proxy.vless.encoding.DelayConfig
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
4, // 3: xray.proxy.vless.encoding.Addons.Scheduler:type_name -> xray.proxy.vless.encoding.SchedulerConfig
|
||||||
0, // [0:0] is the sub-list for field type_name
|
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() }
|
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 {
|
if File_proxy_vless_encoding_addons_proto != nil {
|
||||||
return
|
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{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proxy_vless_encoding_addons_proto_rawDesc,
|
RawDescriptor: file_proxy_vless_encoding_addons_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 1,
|
NumMessages: 4,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_proxy_vless_encoding_addons_proto_goTypes,
|
GoTypes: file_proxy_vless_encoding_addons_proto_goTypes,
|
||||||
DependencyIndexes: file_proxy_vless_encoding_addons_proto_depIdxs,
|
DependencyIndexes: file_proxy_vless_encoding_addons_proto_depIdxs,
|
||||||
|
EnumInfos: file_proxy_vless_encoding_addons_proto_enumTypes,
|
||||||
MessageInfos: file_proxy_vless_encoding_addons_proto_msgTypes,
|
MessageInfos: file_proxy_vless_encoding_addons_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proxy_vless_encoding_addons_proto = out.File
|
File_proxy_vless_encoding_addons_proto = out.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;
|
|
||||||
}
|
|
@ -28,7 +28,7 @@ var addrParser = protocol.NewAddressParser(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EncodeRequestHeader writes encoded request header into the given writer.
|
// 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()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
|
// 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) (*protocol.RequestHeader, *Addons, bool, error) {
|
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) (*protocol.RequestHeader, *proxy.Addons, bool, error) {
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EncodeResponseHeader writes encoded response header into the given writer.
|
// 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()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
|
// 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()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XtlsRead filter and read xtls protocol
|
// XtlsRead filter and read xtls protocol
|
||||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error {
|
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, scheduler *proxy.Scheduler, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
for {
|
for {
|
||||||
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
||||||
@ -188,11 +188,10 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
|
|||||||
ob.CanSpliceCopy = 1
|
ob.CanSpliceCopy = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer, inTimer)
|
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer, inTimer, scheduler)
|
||||||
}
|
}
|
||||||
buffer, err := reader.ReadMultiBuffer()
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
if !buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
timer.Update()
|
|
||||||
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
||||||
// XTLS Vision processes struct TLS Conn's input and rawInput
|
// XTLS Vision processes struct TLS Conn's input and rawInput
|
||||||
if inputBuffer, err := buf.ReadFrom(input); err == nil {
|
if inputBuffer, err := buf.ReadFrom(input); err == nil {
|
||||||
@ -209,7 +208,9 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
|
|||||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
return werr
|
return werr
|
||||||
}
|
}
|
||||||
|
timer.Update()
|
||||||
}
|
}
|
||||||
|
scheduler.Trigger <- 2
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"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"
|
||||||
. "github.com/xtls/xray-core/proxy/vless/encoding"
|
. "github.com/xtls/xray-core/proxy/vless/encoding"
|
||||||
)
|
)
|
||||||
@ -37,7 +38,7 @@ func TestRequestSerialization(t *testing.T) {
|
|||||||
Address: net.DomainAddress("www.example.com"),
|
Address: net.DomainAddress("www.example.com"),
|
||||||
Port: net.Port(443),
|
Port: net.Port(443),
|
||||||
}
|
}
|
||||||
expectedAddons := &Addons{}
|
expectedAddons := &proxy.Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@ -52,7 +53,7 @@ func TestRequestSerialization(t *testing.T) {
|
|||||||
t.Error(r)
|
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))
|
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
||||||
}
|
}
|
||||||
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
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"),
|
Address: net.DomainAddress("www.example.com"),
|
||||||
Port: net.Port(443),
|
Port: net.Port(443),
|
||||||
}
|
}
|
||||||
expectedAddons := &Addons{}
|
expectedAddons := &proxy.Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@ -109,7 +110,7 @@ func TestMuxRequest(t *testing.T) {
|
|||||||
Command: protocol.RequestCommandMux,
|
Command: protocol.RequestCommandMux,
|
||||||
Address: net.DomainAddress("v1.mux.cool"),
|
Address: net.DomainAddress("v1.mux.cool"),
|
||||||
}
|
}
|
||||||
expectedAddons := &Addons{}
|
expectedAddons := &proxy.Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@ -124,7 +125,7 @@ func TestMuxRequest(t *testing.T) {
|
|||||||
t.Error(r)
|
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))
|
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
||||||
}
|
}
|
||||||
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
||||||
|
@ -215,7 +215,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
|
|
||||||
var request *protocol.RequestHeader
|
var request *protocol.RequestHeader
|
||||||
var requestAddons *encoding.Addons
|
var requestAddons *proxy.Addons
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
napfb := h.fallbacks
|
napfb := h.fallbacks
|
||||||
@ -455,8 +455,12 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
account := request.User.Account.(*vless.MemoryAccount)
|
account := request.User.Account.(*vless.MemoryAccount)
|
||||||
|
|
||||||
responseAddons := &encoding.Addons{
|
responseAddons := &proxy.Addons{
|
||||||
// Flow: requestAddons.Flow,
|
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
|
var input *bytes.Reader
|
||||||
@ -527,22 +531,27 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
serverReader := link.Reader // .(*pipe.Reader)
|
serverReader := link.Reader // .(*pipe.Reader)
|
||||||
serverWriter := link.Writer // .(*pipe.Writer)
|
serverWriter := link.Writer // .(*pipe.Writer)
|
||||||
trafficState := proxy.NewTrafficState(account.ID.Bytes())
|
trafficState := proxy.NewTrafficState(account.ID.Bytes(), account.Flow)
|
||||||
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||||
|
var clientWriter buf.Writer
|
||||||
|
v := proxy.NewVisionWriter(bufferWriter, requestAddons, trafficState, false, ctx)
|
||||||
|
scheduler := v.Scheduler
|
||||||
|
clientWriter = v
|
||||||
|
|
||||||
postRequest := func() error {
|
postRequest := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
|
|
||||||
// default: clientReader := reader
|
// default: clientReader := reader
|
||||||
clientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)
|
clientReader := encoding.DecodeBodyAddons(reader, request, responseAddons, trafficState, true, ctx)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||||
clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx1)
|
err = encoding.XtlsRead(clientReader, serverWriter, timer, scheduler, connection, input, rawInput, trafficState, nil, true, ctx1)
|
||||||
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, nil, true, ctx1)
|
|
||||||
} else {
|
} else {
|
||||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
|
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
|
||||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer), proxy.TriggerScheduler(scheduler))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -555,13 +564,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
getResponse := func() error {
|
getResponse := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
|
||||||
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
||||||
return errors.New("failed to encode response header").Base(err).AtWarning()
|
return errors.New("failed to encode response header").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: clientWriter := bufferWriter
|
scheduler.Start()
|
||||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx)
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
|
clientWriter = encoding.NewMultiLengthPacketWriter(clientWriter)
|
||||||
|
}
|
||||||
multiBuffer, err1 := serverReader.ReadMultiBuffer()
|
multiBuffer, err1 := serverReader.ReadMultiBuffer()
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return err1 // ...
|
return err1 // ...
|
||||||
|
@ -116,9 +116,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
account := request.User.Account.(*vless.MemoryAccount)
|
account := request.User.Account.(*vless.MemoryAccount)
|
||||||
|
|
||||||
requestAddons := &encoding.Addons{
|
requestAddons := &proxy.Addons{
|
||||||
Flow: account.Flow,
|
Flow: account.Flow,
|
||||||
}
|
}
|
||||||
|
encoding.PopulateSeed(account.Seed, requestAddons)
|
||||||
|
|
||||||
var input *bytes.Reader
|
var input *bytes.Reader
|
||||||
var rawInput *bytes.Buffer
|
var rawInput *bytes.Buffer
|
||||||
@ -178,24 +179,29 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
clientReader := link.Reader // .(*pipe.Reader)
|
clientReader := link.Reader // .(*pipe.Reader)
|
||||||
clientWriter := link.Writer // .(*pipe.Writer)
|
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)) {
|
if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
|
||||||
request.Command = protocol.RequestCommandMux
|
request.Command = protocol.RequestCommandMux
|
||||||
request.Address = net.DomainAddress("v1.mux.cool")
|
request.Address = net.DomainAddress("v1.mux.cool")
|
||||||
request.Port = net.Port(666)
|
request.Port = net.Port(666)
|
||||||
}
|
}
|
||||||
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||||
|
var serverWriter buf.Writer
|
||||||
|
v := proxy.NewVisionWriter(bufferWriter, requestAddons, trafficState, true, ctx)
|
||||||
|
scheduler := v.Scheduler
|
||||||
|
serverWriter = v
|
||||||
|
|
||||||
postRequest := func() error {
|
postRequest := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
|
||||||
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
||||||
return errors.New("failed to encode request header").Base(err).AtWarning()
|
return errors.New("failed to encode request header").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: serverWriter := bufferWriter
|
scheduler.Start()
|
||||||
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, true, ctx)
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
serverWriter = encoding.NewMultiLengthPacketWriter(serverWriter)
|
||||||
|
} else if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||||
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
|
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
|
||||||
}
|
}
|
||||||
timeoutReader, ok := clientReader.(buf.TimeoutReader)
|
timeoutReader, ok := clientReader.(buf.TimeoutReader)
|
||||||
@ -221,6 +227,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if err := bufferWriter.SetBuffered(false); err != nil {
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
if requestAddons.Scheduler != nil && requestAddons.Scheduler.PingPong {
|
||||||
|
go func() {
|
||||||
|
scheduler.Trigger <- 2 // client kickstart the pingpong!
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
@ -259,23 +270,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// default: serverReader := buf.NewReader(conn)
|
// default: serverReader := buf.NewReader(conn)
|
||||||
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
|
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons, trafficState, false, ctx)
|
||||||
if requestAddons.Flow == vless.XRV {
|
|
||||||
serverReader = proxy.NewVisionReader(serverReader, trafficState, false, ctx)
|
|
||||||
}
|
|
||||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||||
if requestAddons.Flow == vless.XRV {
|
|
||||||
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
|
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
|
||||||
} else {
|
|
||||||
serverReader = xudp.NewPacketReader(conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, false, ctx)
|
err = encoding.XtlsRead(serverReader, clientWriter, timer, scheduler, conn, input, rawInput, trafficState, ob, false, ctx)
|
||||||
} else {
|
} else {
|
||||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
|
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
|
||||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer), proxy.TriggerScheduler(scheduler))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,6 +30,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestVless(t *testing.T) {
|
func TestVless(t *testing.T) {
|
||||||
|
testVlessSeed(t, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVlessSeedWithFixedTrigger(t *testing.T) {
|
||||||
|
testVlessSeed(t, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVlessSeedWithPingPong(t *testing.T) {
|
||||||
|
testVlessSeed(t, "pingpong")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVlessSeed(t *testing.T, seed string) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
}
|
}
|
||||||
@ -57,6 +69,7 @@ func TestVless(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
|
Seed: seed,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -102,6 +115,7 @@ func TestVless(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
|
Seed: seed,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -248,6 +262,18 @@ func TestVlessTls(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVlessXtlsVision(t *testing.T) {
|
func TestVlessXtlsVision(t *testing.T) {
|
||||||
|
testVlessXtlsVisionWithSeed(t, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVlessXtlsVisionWithFixedTrigger(t *testing.T) {
|
||||||
|
testVlessXtlsVisionWithSeed(t, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVlessXtlsVisionWithPingPong(t *testing.T) {
|
||||||
|
testVlessXtlsVisionWithSeed(t, "pingpong")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVlessXtlsVisionWithSeed(t *testing.T, seed string) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
}
|
}
|
||||||
@ -285,6 +311,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
Flow: vless.XRV,
|
Flow: vless.XRV,
|
||||||
|
Seed: seed,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -331,6 +358,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
Flow: vless.XRV,
|
Flow: vless.XRV,
|
||||||
|
Seed: seed,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user