mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-09 05:08:52 +00:00
Finalmask: Add header-custom (TCP & UDP), fragment (TCP), noise (UDP); Support dialer-proxy, XHTTP/3; Fix XDNS, XICMP potential panic (#5657)
https://github.com/XTLS/Xray-core/pull/5657#issuecomment-4016609446
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *TCPConfig) TCP() {
|
||||
}
|
||||
|
||||
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||
return NewConnClientTCP(c, raw)
|
||||
}
|
||||
|
||||
func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||
return NewConnServerTCP(c, raw)
|
||||
}
|
||||
|
||||
func (c *UDPConfig) UDP() {
|
||||
}
|
||||
|
||||
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||
return NewConnClientUDP(c, raw)
|
||||
}
|
||||
|
||||
func (c *UDPConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||
return NewConnServerUDP(c, raw)
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.5
|
||||
// source: transport/internet/finalmask/header/custom/config.proto
|
||||
|
||||
package custom
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
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 TCPItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DelayMin int64 `protobuf:"varint,1,opt,name=delay_min,json=delayMin,proto3" json:"delay_min,omitempty"`
|
||||
DelayMax int64 `protobuf:"varint,2,opt,name=delay_max,json=delayMax,proto3" json:"delay_max,omitempty"`
|
||||
Rand int32 `protobuf:"varint,3,opt,name=rand,proto3" json:"rand,omitempty"`
|
||||
Packet []byte `protobuf:"bytes,4,opt,name=packet,proto3" json:"packet,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TCPItem) Reset() {
|
||||
*x = TCPItem{}
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TCPItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TCPItem) ProtoMessage() {}
|
||||
|
||||
func (x *TCPItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TCPItem.ProtoReflect.Descriptor instead.
|
||||
func (*TCPItem) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *TCPItem) GetDelayMin() int64 {
|
||||
if x != nil {
|
||||
return x.DelayMin
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TCPItem) GetDelayMax() int64 {
|
||||
if x != nil {
|
||||
return x.DelayMax
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TCPItem) GetRand() int32 {
|
||||
if x != nil {
|
||||
return x.Rand
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TCPItem) GetPacket() []byte {
|
||||
if x != nil {
|
||||
return x.Packet
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TCPSequence struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Sequence []*TCPItem `protobuf:"bytes,1,rep,name=sequence,proto3" json:"sequence,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TCPSequence) Reset() {
|
||||
*x = TCPSequence{}
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TCPSequence) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TCPSequence) ProtoMessage() {}
|
||||
|
||||
func (x *TCPSequence) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TCPSequence.ProtoReflect.Descriptor instead.
|
||||
func (*TCPSequence) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *TCPSequence) GetSequence() []*TCPItem {
|
||||
if x != nil {
|
||||
return x.Sequence
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TCPConfig struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Clients []*TCPSequence `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
|
||||
Servers []*TCPSequence `protobuf:"bytes,2,rep,name=servers,proto3" json:"servers,omitempty"`
|
||||
Errors []*TCPSequence `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TCPConfig) Reset() {
|
||||
*x = TCPConfig{}
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TCPConfig) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TCPConfig) ProtoMessage() {}
|
||||
|
||||
func (x *TCPConfig) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TCPConfig.ProtoReflect.Descriptor instead.
|
||||
func (*TCPConfig) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *TCPConfig) GetClients() []*TCPSequence {
|
||||
if x != nil {
|
||||
return x.Clients
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TCPConfig) GetServers() []*TCPSequence {
|
||||
if x != nil {
|
||||
return x.Servers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TCPConfig) GetErrors() []*TCPSequence {
|
||||
if x != nil {
|
||||
return x.Errors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UDPItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Rand int32 `protobuf:"varint,1,opt,name=rand,proto3" json:"rand,omitempty"`
|
||||
Packet []byte `protobuf:"bytes,2,opt,name=packet,proto3" json:"packet,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UDPItem) Reset() {
|
||||
*x = UDPItem{}
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UDPItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UDPItem) ProtoMessage() {}
|
||||
|
||||
func (x *UDPItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UDPItem.ProtoReflect.Descriptor instead.
|
||||
func (*UDPItem) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *UDPItem) GetRand() int32 {
|
||||
if x != nil {
|
||||
return x.Rand
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *UDPItem) GetPacket() []byte {
|
||||
if x != nil {
|
||||
return x.Packet
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UDPConfig struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Client []*UDPItem `protobuf:"bytes,1,rep,name=client,proto3" json:"client,omitempty"`
|
||||
Server []*UDPItem `protobuf:"bytes,2,rep,name=server,proto3" json:"server,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UDPConfig) Reset() {
|
||||
*x = UDPConfig{}
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UDPConfig) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UDPConfig) ProtoMessage() {}
|
||||
|
||||
func (x *UDPConfig) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_custom_config_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UDPConfig.ProtoReflect.Descriptor instead.
|
||||
func (*UDPConfig) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UDPConfig) GetClient() []*UDPItem {
|
||||
if x != nil {
|
||||
return x.Client
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UDPConfig) GetServer() []*UDPItem {
|
||||
if x != nil {
|
||||
return x.Server
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_custom_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_custom_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"7transport/internet/finalmask/header/custom/config.proto\x12/xray.transport.internet.finalmask.header.custom\"o\n" +
|
||||
"\aTCPItem\x12\x1b\n" +
|
||||
"\tdelay_min\x18\x01 \x01(\x03R\bdelayMin\x12\x1b\n" +
|
||||
"\tdelay_max\x18\x02 \x01(\x03R\bdelayMax\x12\x12\n" +
|
||||
"\x04rand\x18\x03 \x01(\x05R\x04rand\x12\x16\n" +
|
||||
"\x06packet\x18\x04 \x01(\fR\x06packet\"c\n" +
|
||||
"\vTCPSequence\x12T\n" +
|
||||
"\bsequence\x18\x01 \x03(\v28.xray.transport.internet.finalmask.header.custom.TCPItemR\bsequence\"\x91\x02\n" +
|
||||
"\tTCPConfig\x12V\n" +
|
||||
"\aclients\x18\x01 \x03(\v2<.xray.transport.internet.finalmask.header.custom.TCPSequenceR\aclients\x12V\n" +
|
||||
"\aservers\x18\x02 \x03(\v2<.xray.transport.internet.finalmask.header.custom.TCPSequenceR\aservers\x12T\n" +
|
||||
"\x06errors\x18\x03 \x03(\v2<.xray.transport.internet.finalmask.header.custom.TCPSequenceR\x06errors\"5\n" +
|
||||
"\aUDPItem\x12\x12\n" +
|
||||
"\x04rand\x18\x01 \x01(\x05R\x04rand\x12\x16\n" +
|
||||
"\x06packet\x18\x02 \x01(\fR\x06packet\"\xaf\x01\n" +
|
||||
"\tUDPConfig\x12P\n" +
|
||||
"\x06client\x18\x01 \x03(\v28.xray.transport.internet.finalmask.header.custom.UDPItemR\x06client\x12P\n" +
|
||||
"\x06server\x18\x02 \x03(\v28.xray.transport.internet.finalmask.header.custom.UDPItemR\x06serverB\xaf\x01\n" +
|
||||
"3com.xray.transport.internet.finalmask.header.customP\x01ZDgithub.com/xtls/xray-core/transport/internet/finalmask/header/custom\xaa\x02/Xray.Transport.Internet.Finalmask.Header.Customb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_custom_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_custom_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_custom_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_custom_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_custom_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_custom_config_proto_rawDesc), len(file_transport_internet_finalmask_header_custom_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_custom_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_custom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_transport_internet_finalmask_header_custom_config_proto_goTypes = []any{
|
||||
(*TCPItem)(nil), // 0: xray.transport.internet.finalmask.header.custom.TCPItem
|
||||
(*TCPSequence)(nil), // 1: xray.transport.internet.finalmask.header.custom.TCPSequence
|
||||
(*TCPConfig)(nil), // 2: xray.transport.internet.finalmask.header.custom.TCPConfig
|
||||
(*UDPItem)(nil), // 3: xray.transport.internet.finalmask.header.custom.UDPItem
|
||||
(*UDPConfig)(nil), // 4: xray.transport.internet.finalmask.header.custom.UDPConfig
|
||||
}
|
||||
var file_transport_internet_finalmask_header_custom_config_proto_depIdxs = []int32{
|
||||
0, // 0: xray.transport.internet.finalmask.header.custom.TCPSequence.sequence:type_name -> xray.transport.internet.finalmask.header.custom.TCPItem
|
||||
1, // 1: xray.transport.internet.finalmask.header.custom.TCPConfig.clients:type_name -> xray.transport.internet.finalmask.header.custom.TCPSequence
|
||||
1, // 2: xray.transport.internet.finalmask.header.custom.TCPConfig.servers:type_name -> xray.transport.internet.finalmask.header.custom.TCPSequence
|
||||
1, // 3: xray.transport.internet.finalmask.header.custom.TCPConfig.errors:type_name -> xray.transport.internet.finalmask.header.custom.TCPSequence
|
||||
3, // 4: xray.transport.internet.finalmask.header.custom.UDPConfig.client:type_name -> xray.transport.internet.finalmask.header.custom.UDPItem
|
||||
3, // 5: xray.transport.internet.finalmask.header.custom.UDPConfig.server:type_name -> xray.transport.internet.finalmask.header.custom.UDPItem
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_custom_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_custom_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_custom_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_custom_config_proto_rawDesc), len(file_transport_internet_finalmask_header_custom_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_custom_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_custom_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_custom_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_custom_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_custom_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_custom_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.custom;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Custom";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/custom";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.custom";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message TCPItem {
|
||||
int64 delay_min = 1;
|
||||
int64 delay_max = 2;
|
||||
int32 rand = 3;
|
||||
bytes packet = 4;
|
||||
}
|
||||
|
||||
message TCPSequence {
|
||||
repeated TCPItem sequence = 1;
|
||||
}
|
||||
|
||||
message TCPConfig {
|
||||
repeated TCPSequence clients = 1;
|
||||
repeated TCPSequence servers = 2;
|
||||
repeated TCPSequence errors = 3;
|
||||
}
|
||||
|
||||
message UDPItem {
|
||||
int32 rand = 1;
|
||||
bytes packet = 2;
|
||||
}
|
||||
|
||||
message UDPConfig {
|
||||
repeated UDPItem client = 1;
|
||||
repeated UDPItem server = 2;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type tcpCustomClient struct {
|
||||
clients []*TCPSequence
|
||||
servers []*TCPSequence
|
||||
}
|
||||
|
||||
type tcpCustomClientConn struct {
|
||||
net.Conn
|
||||
header *tcpCustomClient
|
||||
|
||||
auth bool
|
||||
wg sync.WaitGroup
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func NewConnClientTCP(c *TCPConfig, raw net.Conn) (net.Conn, error) {
|
||||
conn := &tcpCustomClientConn{
|
||||
Conn: raw,
|
||||
header: &tcpCustomClient{
|
||||
clients: c.Clients,
|
||||
servers: c.Servers,
|
||||
},
|
||||
}
|
||||
|
||||
conn.wg.Add(1)
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *tcpCustomClientConn) TcpMaskConn() {}
|
||||
|
||||
func (c *tcpCustomClientConn) RawConn() net.Conn {
|
||||
// c.wg.Wait()
|
||||
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
func (c *tcpCustomClientConn) Splice() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *tcpCustomClientConn) Read(p []byte) (n int, err error) {
|
||||
c.wg.Wait()
|
||||
|
||||
if !c.auth {
|
||||
return 0, errors.New("header auth failed")
|
||||
}
|
||||
|
||||
return c.Conn.Read(p)
|
||||
}
|
||||
|
||||
func (c *tcpCustomClientConn) Write(p []byte) (n int, err error) {
|
||||
c.once.Do(func() {
|
||||
i := 0
|
||||
j := 0
|
||||
for i = range c.header.clients {
|
||||
if !writeSequence(c.Conn, c.header.clients[i]) {
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
if j < len(c.header.servers) {
|
||||
if !readSequence(c.Conn, c.header.servers[j]) {
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
for j < len(c.header.servers) {
|
||||
if !readSequence(c.Conn, c.header.servers[j]) {
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
c.auth = true
|
||||
c.wg.Done()
|
||||
})
|
||||
|
||||
c.wg.Wait()
|
||||
|
||||
if !c.auth {
|
||||
return 0, errors.New("header auth failed")
|
||||
}
|
||||
|
||||
return c.Conn.Write(p)
|
||||
}
|
||||
|
||||
type tcpCustomServer struct {
|
||||
clients []*TCPSequence
|
||||
servers []*TCPSequence
|
||||
errors []*TCPSequence
|
||||
}
|
||||
|
||||
type tcpCustomServerConn struct {
|
||||
net.Conn
|
||||
header *tcpCustomServer
|
||||
|
||||
auth bool
|
||||
wg sync.WaitGroup
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func NewConnServerTCP(c *TCPConfig, raw net.Conn) (net.Conn, error) {
|
||||
conn := &tcpCustomServerConn{
|
||||
Conn: raw,
|
||||
header: &tcpCustomServer{
|
||||
clients: c.Clients,
|
||||
servers: c.Servers,
|
||||
errors: c.Errors,
|
||||
},
|
||||
}
|
||||
|
||||
conn.wg.Add(1)
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *tcpCustomServerConn) TcpMaskConn() {}
|
||||
|
||||
func (c *tcpCustomServerConn) RawConn() net.Conn {
|
||||
// c.wg.Wait()
|
||||
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
func (c *tcpCustomServerConn) Splice() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *tcpCustomServerConn) Read(p []byte) (n int, err error) {
|
||||
c.once.Do(func() {
|
||||
i := 0
|
||||
j := 0
|
||||
for i = range c.header.clients {
|
||||
if !readSequence(c.Conn, c.header.clients[i]) {
|
||||
if i < len(c.header.errors) {
|
||||
writeSequence(c.Conn, c.header.errors[i])
|
||||
}
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
if j < len(c.header.servers) {
|
||||
if !writeSequence(c.Conn, c.header.servers[j]) {
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
for j < len(c.header.servers) {
|
||||
if !writeSequence(c.Conn, c.header.servers[j]) {
|
||||
c.wg.Done()
|
||||
return
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
c.auth = true
|
||||
c.wg.Done()
|
||||
})
|
||||
|
||||
c.wg.Wait()
|
||||
|
||||
if !c.auth {
|
||||
return 0, errors.New("header auth failed")
|
||||
}
|
||||
|
||||
return c.Conn.Read(p)
|
||||
}
|
||||
|
||||
func (c *tcpCustomServerConn) Write(p []byte) (n int, err error) {
|
||||
c.wg.Wait()
|
||||
|
||||
if !c.auth {
|
||||
return 0, errors.New("header auth failed")
|
||||
}
|
||||
|
||||
return c.Conn.Write(p)
|
||||
}
|
||||
|
||||
func readSequence(r io.Reader, sequence *TCPSequence) bool {
|
||||
for _, item := range sequence.Sequence {
|
||||
length := max(int(item.Rand), len(item.Packet))
|
||||
buf := make([]byte, length)
|
||||
n, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if item.Rand > 0 && n != length {
|
||||
return false
|
||||
}
|
||||
if len(item.Packet) > 0 && !bytes.Equal(item.Packet, buf[:n]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func writeSequence(w io.Writer, sequence *TCPSequence) bool {
|
||||
var merged []byte
|
||||
for _, item := range sequence.Sequence {
|
||||
if item.DelayMax > 0 {
|
||||
if len(merged) > 0 {
|
||||
_, err := w.Write(merged)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
merged = nil
|
||||
}
|
||||
time.Sleep(time.Duration(crypto.RandBetween(item.DelayMin, item.DelayMax)) * time.Millisecond)
|
||||
}
|
||||
if item.Rand > 0 {
|
||||
buf := make([]byte, item.Rand)
|
||||
common.Must2(rand.Read(buf))
|
||||
merged = append(merged, buf...)
|
||||
} else {
|
||||
merged = append(merged, item.Packet...)
|
||||
}
|
||||
}
|
||||
if len(merged) > 0 {
|
||||
_, err := w.Write(merged)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
merged = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"net"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||
)
|
||||
|
||||
type udpCustomClient struct {
|
||||
client []*UDPItem
|
||||
server []*UDPItem
|
||||
merged []byte
|
||||
}
|
||||
|
||||
func (h *udpCustomClient) Serialize(b []byte) {
|
||||
index := 0
|
||||
for _, item := range h.client {
|
||||
if item.Rand > 0 {
|
||||
common.Must2(rand.Read(h.merged[index : index+int(item.Rand)]))
|
||||
index += int(item.Rand)
|
||||
} else {
|
||||
index += len(item.Packet)
|
||||
}
|
||||
}
|
||||
copy(b, h.merged)
|
||||
}
|
||||
|
||||
func (h *udpCustomClient) Match(b []byte) bool {
|
||||
if len(b) < len(h.merged) {
|
||||
return false
|
||||
}
|
||||
|
||||
data := b
|
||||
match := true
|
||||
|
||||
for _, item := range h.server {
|
||||
length := max(int(item.Rand), len(item.Packet))
|
||||
|
||||
if len(item.Packet) > 0 && !bytes.Equal(item.Packet, data[:length]) {
|
||||
match = false
|
||||
break
|
||||
}
|
||||
|
||||
data = data[length:]
|
||||
}
|
||||
|
||||
return match
|
||||
}
|
||||
|
||||
type udpCustomClientConn struct {
|
||||
net.PacketConn
|
||||
header *udpCustomClient
|
||||
}
|
||||
|
||||
func NewConnClientUDP(c *UDPConfig, raw net.PacketConn) (net.PacketConn, error) {
|
||||
conn := &udpCustomClientConn{
|
||||
PacketConn: raw,
|
||||
header: &udpCustomClient{
|
||||
client: c.Client,
|
||||
server: c.Server,
|
||||
},
|
||||
}
|
||||
|
||||
index := 0
|
||||
for _, item := range conn.header.client {
|
||||
if item.Rand > 0 {
|
||||
conn.header.merged = append(conn.header.merged, make([]byte, item.Rand)...)
|
||||
index += int(item.Rand)
|
||||
} else {
|
||||
conn.header.merged = append(conn.header.merged, item.Packet...)
|
||||
index += len(item.Packet)
|
||||
}
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *udpCustomClientConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
buf := p
|
||||
if len(p) < finalmask.UDPSize {
|
||||
buf = make([]byte, finalmask.UDPSize)
|
||||
}
|
||||
|
||||
n, addr, err = c.PacketConn.ReadFrom(buf)
|
||||
if err != nil || n == 0 {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if !c.header.Match(buf[:n]) {
|
||||
errors.LogDebug(context.Background(), addr, " mask read err header mismatch")
|
||||
return 0, addr, nil
|
||||
}
|
||||
|
||||
if len(p) < n-len(c.header.merged) {
|
||||
errors.LogDebug(context.Background(), addr, " mask read err short buffer ", len(p), " ", n-len(c.header.merged))
|
||||
return 0, addr, nil
|
||||
}
|
||||
|
||||
copy(p, buf[len(c.header.merged):n])
|
||||
|
||||
return n - len(c.header.merged), addr, nil
|
||||
}
|
||||
|
||||
func (c *udpCustomClientConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if len(c.header.merged)+len(p) > finalmask.UDPSize {
|
||||
errors.LogDebug(context.Background(), addr, " mask write err short write ", len(c.header.merged)+len(p), " ", finalmask.UDPSize)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
if cap(p) != finalmask.UDPSize {
|
||||
buf = make([]byte, finalmask.UDPSize)
|
||||
} else {
|
||||
buf = p[:len(c.header.merged)+len(p)]
|
||||
}
|
||||
|
||||
copy(buf[len(c.header.merged):], p)
|
||||
c.header.Serialize(buf)
|
||||
|
||||
_, err = c.PacketConn.WriteTo(buf[:len(c.header.merged)+len(p)], addr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
type udpCustomServer struct {
|
||||
client []*UDPItem
|
||||
server []*UDPItem
|
||||
merged []byte
|
||||
}
|
||||
|
||||
func (h *udpCustomServer) Serialize(b []byte) {
|
||||
index := 0
|
||||
for _, item := range h.server {
|
||||
if item.Rand > 0 {
|
||||
common.Must2(rand.Read(h.merged[index : index+int(item.Rand)]))
|
||||
index += int(item.Rand)
|
||||
} else {
|
||||
index += len(item.Packet)
|
||||
}
|
||||
}
|
||||
copy(b, h.merged)
|
||||
}
|
||||
|
||||
func (h *udpCustomServer) Match(b []byte) bool {
|
||||
if len(b) < len(h.merged) {
|
||||
return false
|
||||
}
|
||||
|
||||
data := b
|
||||
match := true
|
||||
|
||||
for _, item := range h.client {
|
||||
length := max(int(item.Rand), len(item.Packet))
|
||||
|
||||
if len(item.Packet) > 0 && !bytes.Equal(item.Packet, data[:length]) {
|
||||
match = false
|
||||
break
|
||||
}
|
||||
|
||||
data = data[length:]
|
||||
}
|
||||
|
||||
return match
|
||||
}
|
||||
|
||||
type udpCustomServerConn struct {
|
||||
net.PacketConn
|
||||
header *udpCustomServer
|
||||
}
|
||||
|
||||
func NewConnServerUDP(c *UDPConfig, raw net.PacketConn) (net.PacketConn, error) {
|
||||
conn := &udpCustomServerConn{
|
||||
PacketConn: raw,
|
||||
header: &udpCustomServer{
|
||||
client: c.Client,
|
||||
server: c.Server,
|
||||
},
|
||||
}
|
||||
|
||||
index := 0
|
||||
for _, item := range conn.header.server {
|
||||
if item.Rand > 0 {
|
||||
conn.header.merged = append(conn.header.merged, make([]byte, item.Rand)...)
|
||||
index += int(item.Rand)
|
||||
} else {
|
||||
conn.header.merged = append(conn.header.merged, item.Packet...)
|
||||
index += len(item.Packet)
|
||||
}
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *udpCustomServerConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
buf := p
|
||||
if len(p) < finalmask.UDPSize {
|
||||
buf = make([]byte, finalmask.UDPSize)
|
||||
}
|
||||
|
||||
n, addr, err = c.PacketConn.ReadFrom(buf)
|
||||
if err != nil || n == 0 {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if !c.header.Match(buf[:n]) {
|
||||
errors.LogDebug(context.Background(), addr, " mask read err header mismatch")
|
||||
return 0, addr, nil
|
||||
}
|
||||
|
||||
if len(p) < n-len(c.header.merged) {
|
||||
errors.LogDebug(context.Background(), addr, " mask read err short buffer ", len(p), " ", n-len(c.header.merged))
|
||||
return 0, addr, nil
|
||||
}
|
||||
|
||||
copy(p, buf[len(c.header.merged):n])
|
||||
|
||||
return n - len(c.header.merged), addr, nil
|
||||
}
|
||||
|
||||
func (c *udpCustomServerConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if len(c.header.merged)+len(p) > finalmask.UDPSize {
|
||||
errors.LogDebug(context.Background(), addr, " mask write err short write ", len(c.header.merged)+len(p), " ", finalmask.UDPSize)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
if cap(p) != finalmask.UDPSize {
|
||||
buf = make([]byte, finalmask.UDPSize)
|
||||
} else {
|
||||
buf = p[:len(c.header.merged)+len(p)]
|
||||
}
|
||||
|
||||
copy(buf[len(c.header.merged):], p)
|
||||
c.header.Serialize(buf)
|
||||
|
||||
_, err = c.PacketConn.WriteTo(buf[:len(c.header.merged)+len(p)], addr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
Reference in New Issue
Block a user