mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-10-19 16:17:34 +00:00
add transport layer padding support to tlsmirror
This commit is contained in:
committed by
Xiaokang Wang (Shelikhoo)
parent
f59383bb82
commit
284d1891c6
@@ -168,15 +168,16 @@ func (d *persistentMirrorTLSDialer) handleIncomingCarrierConnection(ctx context.
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
cconnState := &clientConnState{
|
||||
ctx: ctx,
|
||||
done: cancel,
|
||||
localAddr: conn.LocalAddr(),
|
||||
remoteAddr: conn.RemoteAddr(),
|
||||
handler: d.handleIncomingReadyConnection,
|
||||
primaryKey: d.config.PrimaryKey,
|
||||
readPipe: make(chan []byte, 1),
|
||||
firstWrite: true,
|
||||
firstWriteDelay: firstWriteDelay,
|
||||
ctx: ctx,
|
||||
done: cancel,
|
||||
localAddr: conn.LocalAddr(),
|
||||
remoteAddr: conn.RemoteAddr(),
|
||||
handler: d.handleIncomingReadyConnection,
|
||||
primaryKey: d.config.PrimaryKey,
|
||||
readPipe: make(chan []byte, 1),
|
||||
firstWrite: true,
|
||||
firstWriteDelay: firstWriteDelay,
|
||||
transportLayerPadding: d.config.TransportLayerPadding,
|
||||
}
|
||||
|
||||
cconnState.mirrorConn = mirrorbase.NewMirroredTLSConn(ctx, conn, forwardConn, cconnState.onC2SMessage, cconnState.onS2CMessage, conn,
|
||||
|
||||
@@ -35,6 +35,8 @@ type clientConnState struct {
|
||||
|
||||
firstWrite bool
|
||||
firstWriteDelay time.Duration
|
||||
|
||||
transportLayerPadding *TransportLayerPadding
|
||||
}
|
||||
|
||||
func (s *clientConnState) GetConnectionContext() context.Context {
|
||||
@@ -54,6 +56,14 @@ func (s *clientConnState) Read(b []byte) (n int, err error) {
|
||||
case <-s.ctx.Done():
|
||||
return 0, s.ctx.Err()
|
||||
case data := <-s.readPipe:
|
||||
if s.transportLayerPadding != nil && s.transportLayerPadding.Enabled {
|
||||
var padding int
|
||||
data, padding = Unpack(data)
|
||||
_ = padding
|
||||
if data == nil {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
s.readBuffer = bytes.NewBuffer(data)
|
||||
n, err = s.readBuffer.Read(b)
|
||||
if err != nil {
|
||||
@@ -74,6 +84,9 @@ func (s *clientConnState) Write(b []byte) (n int, err error) {
|
||||
s.firstWrite = false
|
||||
}
|
||||
}
|
||||
if s.transportLayerPadding != nil && s.transportLayerPadding.Enabled {
|
||||
b = Pack(b, 0)
|
||||
}
|
||||
err = s.WriteMessage(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -69,6 +69,50 @@ func (x *TimeSpec) GetUniformRandomMultiplierNanoseconds() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type TransportLayerPadding struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TransportLayerPadding) Reset() {
|
||||
*x = TransportLayerPadding{}
|
||||
mi := &file_transport_internet_tlsmirror_server_config_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TransportLayerPadding) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TransportLayerPadding) ProtoMessage() {}
|
||||
|
||||
func (x *TransportLayerPadding) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_tlsmirror_server_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 TransportLayerPadding.ProtoReflect.Descriptor instead.
|
||||
func (*TransportLayerPadding) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_tlsmirror_server_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *TransportLayerPadding) GetEnabled() bool {
|
||||
if x != nil {
|
||||
return x.Enabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ForwardAddress string `protobuf:"bytes,1,opt,name=forward_address,json=forwardAddress,proto3" json:"forward_address,omitempty"`
|
||||
@@ -79,13 +123,14 @@ type Config struct {
|
||||
PrimaryKey []byte `protobuf:"bytes,6,opt,name=primary_key,json=primaryKey,proto3" json:"primary_key,omitempty"`
|
||||
ExplicitNonceCiphersuites []uint32 `protobuf:"varint,7,rep,packed,name=explicit_nonce_ciphersuites,json=explicitNonceCiphersuites,proto3" json:"explicit_nonce_ciphersuites,omitempty"`
|
||||
DeferFirstPayloadWriteTime *TimeSpec `protobuf:"bytes,8,opt,name=defer_first_payload_write_time,json=deferFirstPayloadWriteTime,proto3" json:"defer_first_payload_write_time,omitempty"`
|
||||
TransportLayerPadding *TransportLayerPadding `protobuf:"bytes,9,opt,name=transport_layer_padding,json=transportLayerPadding,proto3" json:"transport_layer_padding,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_tlsmirror_server_config_proto_msgTypes[1]
|
||||
mi := &file_transport_internet_tlsmirror_server_config_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -97,7 +142,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_tlsmirror_server_config_proto_msgTypes[1]
|
||||
mi := &file_transport_internet_tlsmirror_server_config_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -110,7 +155,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_tlsmirror_server_config_proto_rawDescGZIP(), []int{1}
|
||||
return file_transport_internet_tlsmirror_server_config_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Config) GetForwardAddress() string {
|
||||
@@ -169,6 +214,13 @@ func (x *Config) GetDeferFirstPayloadWriteTime() *TimeSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Config) GetTransportLayerPadding() *TransportLayerPadding {
|
||||
if x != nil {
|
||||
return x.TransportLayerPadding
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_transport_internet_tlsmirror_server_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_tlsmirror_server_config_proto_rawDesc = "" +
|
||||
@@ -176,7 +228,9 @@ const file_transport_internet_tlsmirror_server_config_proto_rawDesc = "" +
|
||||
"0transport/internet/tlsmirror/server/config.proto\x12.v2ray.core.transport.internet.tlsmirror.server\x1a common/protoext/extensions.proto\x1a7transport/internet/tlsmirror/tlstrafficgen/config.proto\"\x88\x01\n" +
|
||||
"\bTimeSpec\x12)\n" +
|
||||
"\x10base_nanoseconds\x18\x01 \x01(\x04R\x0fbaseNanoseconds\x12Q\n" +
|
||||
"%uniform_random_multiplier_nanoseconds\x18\x02 \x01(\x04R\"uniformRandomMultiplierNanoseconds\"\xb4\x04\n" +
|
||||
"%uniform_random_multiplier_nanoseconds\x18\x02 \x01(\x04R\"uniformRandomMultiplierNanoseconds\"1\n" +
|
||||
"\x15TransportLayerPadding\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\"\xb3\x05\n" +
|
||||
"\x06Config\x12'\n" +
|
||||
"\x0fforward_address\x18\x01 \x01(\tR\x0eforwardAddress\x12!\n" +
|
||||
"\fforward_port\x18\x02 \x01(\rR\vforwardPort\x12\x1f\n" +
|
||||
@@ -187,7 +241,8 @@ const file_transport_internet_tlsmirror_server_config_proto_rawDesc = "" +
|
||||
"\vprimary_key\x18\x06 \x01(\fR\n" +
|
||||
"primaryKey\x12>\n" +
|
||||
"\x1bexplicit_nonce_ciphersuites\x18\a \x03(\rR\x19explicitNonceCiphersuites\x12|\n" +
|
||||
"\x1edefer_first_payload_write_time\x18\b \x01(\v28.v2ray.core.transport.internet.tlsmirror.server.TimeSpecR\x1adeferFirstPayloadWriteTime:+\x82\xb5\x18'\n" +
|
||||
"\x1edefer_first_payload_write_time\x18\b \x01(\v28.v2ray.core.transport.internet.tlsmirror.server.TimeSpecR\x1adeferFirstPayloadWriteTime\x12}\n" +
|
||||
"\x17transport_layer_padding\x18\t \x01(\v2E.v2ray.core.transport.internet.tlsmirror.server.TransportLayerPaddingR\x15transportLayerPadding:+\x82\xb5\x18'\n" +
|
||||
"\ttransport\x12\ttlsmirror\x8a\xff)\ttlsmirror\x90\xff)\x01B\xab\x01\n" +
|
||||
"2com.v2ray.core.transport.internet.tlsmirror.serverP\x01ZBgithub.com/v2fly/v2ray-core/v5/transport/internet/tlsmirror/server\xaa\x02.V2Ray.Core.Transport.Internet.Tlsmirror.Serverb\x06proto3"
|
||||
|
||||
@@ -203,20 +258,22 @@ func file_transport_internet_tlsmirror_server_config_proto_rawDescGZIP() []byte
|
||||
return file_transport_internet_tlsmirror_server_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_tlsmirror_server_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_transport_internet_tlsmirror_server_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_transport_internet_tlsmirror_server_config_proto_goTypes = []any{
|
||||
(*TimeSpec)(nil), // 0: v2ray.core.transport.internet.tlsmirror.server.TimeSpec
|
||||
(*Config)(nil), // 1: v2ray.core.transport.internet.tlsmirror.server.Config
|
||||
(*tlstrafficgen.Config)(nil), // 2: v2ray.core.transport.internet.tlsmirror.tlstrafficgen.Config
|
||||
(*TimeSpec)(nil), // 0: v2ray.core.transport.internet.tlsmirror.server.TimeSpec
|
||||
(*TransportLayerPadding)(nil), // 1: v2ray.core.transport.internet.tlsmirror.server.TransportLayerPadding
|
||||
(*Config)(nil), // 2: v2ray.core.transport.internet.tlsmirror.server.Config
|
||||
(*tlstrafficgen.Config)(nil), // 3: v2ray.core.transport.internet.tlsmirror.tlstrafficgen.Config
|
||||
}
|
||||
var file_transport_internet_tlsmirror_server_config_proto_depIdxs = []int32{
|
||||
2, // 0: v2ray.core.transport.internet.tlsmirror.server.Config.embedded_traffic_generator:type_name -> v2ray.core.transport.internet.tlsmirror.tlstrafficgen.Config
|
||||
3, // 0: v2ray.core.transport.internet.tlsmirror.server.Config.embedded_traffic_generator:type_name -> v2ray.core.transport.internet.tlsmirror.tlstrafficgen.Config
|
||||
0, // 1: v2ray.core.transport.internet.tlsmirror.server.Config.defer_first_payload_write_time:type_name -> v2ray.core.transport.internet.tlsmirror.server.TimeSpec
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
1, // 2: v2ray.core.transport.internet.tlsmirror.server.Config.transport_layer_padding:type_name -> v2ray.core.transport.internet.tlsmirror.server.TransportLayerPadding
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_tlsmirror_server_config_proto_init() }
|
||||
@@ -230,7 +287,7 @@ func file_transport_internet_tlsmirror_server_config_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_tlsmirror_server_config_proto_rawDesc), len(file_transport_internet_tlsmirror_server_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -14,6 +14,10 @@ message TimeSpec {
|
||||
uint64 uniform_random_multiplier_nanoseconds = 2;
|
||||
}
|
||||
|
||||
message TransportLayerPadding {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
message Config {
|
||||
option (v2ray.core.common.protoext.message_opt).type = "transport";
|
||||
option (v2ray.core.common.protoext.message_opt).short_name = "tlsmirror";
|
||||
@@ -34,4 +38,6 @@ message Config {
|
||||
repeated uint32 explicit_nonce_ciphersuites = 7;
|
||||
|
||||
TimeSpec defer_first_payload_write_time = 8;
|
||||
|
||||
TransportLayerPadding transport_layer_padding = 9;
|
||||
}
|
||||
@@ -31,6 +31,8 @@ type connState struct {
|
||||
readBuffer *bytes.Buffer
|
||||
|
||||
protocolVersion [2]byte
|
||||
|
||||
transportLayerPadding *TransportLayerPadding
|
||||
}
|
||||
|
||||
func (s *connState) Read(b []byte) (n int, err error) {
|
||||
@@ -46,6 +48,14 @@ func (s *connState) Read(b []byte) (n int, err error) {
|
||||
case <-s.ctx.Done():
|
||||
return 0, s.ctx.Err()
|
||||
case data := <-s.readPipe:
|
||||
if s.transportLayerPadding != nil && s.transportLayerPadding.Enabled {
|
||||
var padding int
|
||||
data, padding = Unpack(data)
|
||||
_ = padding
|
||||
if data == nil {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
s.readBuffer = bytes.NewBuffer(data)
|
||||
n, err = s.readBuffer.Read(b)
|
||||
if err != nil {
|
||||
@@ -56,6 +66,9 @@ func (s *connState) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (s *connState) Write(b []byte) (n int, err error) {
|
||||
if s.transportLayerPadding != nil && s.transportLayerPadding.Enabled {
|
||||
b = Pack(b, 0)
|
||||
}
|
||||
err = s.WriteMessage(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package server
|
||||
|
||||
// this file defines methods to pad packets
|
||||
// with a given number of bytes, and to unpack the padding from a padded packet.
|
||||
// The packet format is as follows if the desired output length is greater than
|
||||
// 4 bytes:
|
||||
// | data | padding | data length |
|
||||
// The data length is a 32-bit big-endian integer that represents the length of
|
||||
// the data in bytes.
|
||||
// If the desired output length is 4 bytes or less, the packet format is as
|
||||
// follows:
|
||||
// | padding |
|
||||
// No payload will be included in the packet.
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// Pack pads the given data with the given number of bytes, and appends the
|
||||
// length of the data to the end of the data. The returned byte slice
|
||||
// contains the padded data.
|
||||
// This generates a packet with a length of
|
||||
// len(data_OWNERSHIP_RELINQUISHED) + padding + 2
|
||||
// @param data_OWNERSHIP_RELINQUISHED - The payload, this reference is consumed and should not be used after this call.
|
||||
// @param padding - The number of padding bytes to add to the data.
|
||||
func Pack(data_OWNERSHIP_RELINQUISHED []byte, paddingLength int) []byte {
|
||||
data := append(data_OWNERSHIP_RELINQUISHED, make([]byte, paddingLength)...)
|
||||
dataLength := len(data_OWNERSHIP_RELINQUISHED)
|
||||
data = binary.BigEndian.AppendUint32(data, uint32(dataLength))
|
||||
return data
|
||||
}
|
||||
|
||||
// Pad returns a padding packet of padding length.
|
||||
// If the padding length is less than 0, nil is returned.
|
||||
// @param padding - The number of padding bytes to add to the data.
|
||||
func Pad(paddingLength int) []byte {
|
||||
if assertPaddingLengthIsNotNegative := paddingLength < 0; assertPaddingLengthIsNotNegative {
|
||||
return nil
|
||||
}
|
||||
switch paddingLength {
|
||||
case 0:
|
||||
return []byte{}
|
||||
case 1:
|
||||
return []byte{0}
|
||||
case 2:
|
||||
return []byte{0, 0}
|
||||
case 3:
|
||||
return []byte{0, 0, 0}
|
||||
case 4:
|
||||
return []byte{0, 0, 0, 0}
|
||||
default:
|
||||
return append(make([]byte, paddingLength-4), byte(paddingLength>>24), byte(paddingLength>>16), byte(paddingLength>>8), byte(paddingLength))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Unpack extracts the data and padding from the given padded data. It
|
||||
// returns the data and the number of padding bytes.
|
||||
// the data may be nil.
|
||||
// @param wrappedData_OWNERSHIP_RELINQUISHED - The packet, this reference is consumed and should not be used after this call.
|
||||
func Unpack(wrappedData_OWNERSHIP_RELINQUISHED []byte) ([]byte, int) {
|
||||
dataLength := len(wrappedData_OWNERSHIP_RELINQUISHED)
|
||||
if dataLength < 4 {
|
||||
return nil, dataLength
|
||||
}
|
||||
|
||||
dataLen := int(binary.BigEndian.Uint32(wrappedData_OWNERSHIP_RELINQUISHED[dataLength-4:]))
|
||||
if dataLen > len(wrappedData_OWNERSHIP_RELINQUISHED)-4 {
|
||||
return nil, 0
|
||||
}
|
||||
paddingLength := dataLength - dataLen - 4
|
||||
if paddingLength < 0 {
|
||||
return nil, paddingLength
|
||||
}
|
||||
|
||||
return wrappedData_OWNERSHIP_RELINQUISHED[:dataLen], paddingLength
|
||||
}
|
||||
Reference in New Issue
Block a user