Improve VLESS request

This commit is contained in:
世界 2023-04-18 14:59:44 +08:00
parent a62ad44883
commit 8eb7dd0059
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
7 changed files with 354 additions and 161 deletions

View file

@ -135,7 +135,7 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn
hello.SessionId[0] = 1 hello.SessionId[0] = 1
hello.SessionId[1] = 8 hello.SessionId[1] = 8
hello.SessionId[2] = 0 hello.SessionId[2] = 1
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix())) binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
copy(hello.SessionId[8:], e.shortID[:]) copy(hello.SessionId[8:], e.shortID[:])

View file

@ -141,6 +141,95 @@ func TestVLESSVisionReality(t *testing.T) {
testSuit(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func TestVLESSVisionRealityPlain(t *testing.T) {
userUUID := newUUID()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
{
Type: C.TypeVLESS,
VLESSOptions: option.VLESSInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Users: []option.VLESSUser{
{
Name: "sekai",
UUID: userUUID.String(),
Flow: vless.FlowVision,
},
},
TLS: &option.InboundTLSOptions{
Enabled: true,
ServerName: "google.com",
Reality: &option.InboundRealityOptions{
Enabled: true,
Handshake: option.InboundRealityHandshakeOptions{
ServerOptions: option.ServerOptions{
Server: "google.com",
ServerPort: 443,
},
},
ShortID: []string{"0123456789abcdef"},
PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc",
},
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeVLESS,
Tag: "vless-out",
VLESSOptions: option.VLESSOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: userUUID.String(),
Flow: vless.FlowVision,
TLS: &option.OutboundTLSOptions{
Enabled: true,
ServerName: "google.com",
Reality: &option.OutboundRealityOptions{
Enabled: true,
ShortID: "0123456789abcdef",
PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0",
},
UTLS: &option.OutboundUTLSOptions{
Enabled: true,
},
},
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "vless-out",
},
},
},
},
})
testSuit(t, clientPort, testPort)
}
func TestVLESSRealityTransport(t *testing.T) { func TestVLESSRealityTransport(t *testing.T) {
t.Run("grpc", func(t *testing.T) { t.Run("grpc", func(t *testing.T) {
testVLESSRealityTransport(t, &option.V2RayTransportOptions{ testVLESSRealityTransport(t, &option.V2RayTransportOptions{
@ -160,8 +249,6 @@ func TestVLESSRealityTransport(t *testing.T) {
} }
func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) { func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
userUUID := newUUID() userUUID := newUUID()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
@ -206,52 +293,11 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
Transport: transport, Transport: transport,
}, },
}, },
{
Type: C.TypeTrojan,
Tag: "trojan",
TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: otherPort,
},
Users: []option.TrojanUser{
{
Name: "sekai",
Password: userUUID.String(),
},
},
TLS: &option.InboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
KeyPath: keyPem,
},
},
},
}, },
Outbounds: []option.Outbound{ Outbounds: []option.Outbound{
{ {
Type: C.TypeDirect, Type: C.TypeDirect,
}, },
{
Type: C.TypeTrojan,
Tag: "trojan-out",
TrojanOptions: option.TrojanOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: otherPort,
},
Password: userUUID.String(),
TLS: &option.OutboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
},
DialerOptions: option.DialerOptions{
Detour: "vless-out",
},
},
},
{ {
Type: C.TypeVLESS, Type: C.TypeVLESS,
Tag: "vless-out", Tag: "vless-out",
@ -282,7 +328,7 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
{ {
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"}, Inbound: []string{"mixed-in"},
Outbound: "trojan-out", Outbound: "vless-out",
}, },
}, },
}, },

View file

@ -8,6 +8,7 @@ import (
"github.com/sagernet/sing-vmess" "github.com/sagernet/sing-vmess"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
@ -35,32 +36,28 @@ func NewClient(userId string, flow string, logger logger.Logger) (*Client, error
return &Client{user, flow, logger}, nil return &Client{user, flow, logger}, nil
} }
func (c *Client) prepareConn(conn net.Conn) (net.Conn, error) { func (c *Client) prepareConn(conn net.Conn, tlsConn net.Conn) (net.Conn, error) {
if c.flow == FlowVision { if c.flow == FlowVision {
vConn, err := NewVisionConn(conn, c.key, c.logger) protocolConn, err := NewVisionConn(conn, tlsConn, c.key, c.logger)
if err != nil { if err != nil {
return nil, E.Cause(err, "initialize vision") return nil, E.Cause(err, "initialize vision")
} }
conn = vConn conn = protocolConn
} }
return conn, nil return conn, nil
} }
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) { func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
vConn, err := c.prepareConn(conn) remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
serverConn := &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow} return protocolConn, common.Error(remoteConn.Write(nil))
return serverConn, common.Error(serverConn.Write(nil))
} }
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) { func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
vConn, err := c.prepareConn(conn) return c.prepareConn(NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow), conn)
if err != nil {
return nil, err
}
return &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}, nil
} }
func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) (*PacketConn, error) { func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) (*PacketConn, error) {
@ -73,71 +70,122 @@ func (c *Client) DialEarlyPacketConn(conn net.Conn, destination M.Socksaddr) (*P
} }
func (c *Client) DialXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) { func (c *Client) DialXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
serverConn := &Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow} remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
err := common.Error(serverConn.Write(nil)) protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return vmess.NewXUDPConn(serverConn, destination), nil return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
} }
func (c *Client) DialEarlyXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) { func (c *Client) DialEarlyXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
return vmess.NewXUDPConn(&Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}, destination), nil remoteConn := NewConn(conn, c.key, vmess.CommandMux, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil {
return nil, err
}
return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
} }
var _ N.EarlyConn = (*Conn)(nil) var (
_ N.EarlyConn = (*Conn)(nil)
_ N.VectorisedWriter = (*Conn)(nil)
)
type Conn struct { type Conn struct {
net.Conn N.ExtendedConn
protocolConn net.Conn writer N.VectorisedWriter
key [16]byte request Request
command byte
destination M.Socksaddr
flow string
requestWritten bool requestWritten bool
responseRead bool responseRead bool
} }
func NewConn(conn net.Conn, uuid [16]byte, command byte, destination M.Socksaddr, flow string) *Conn {
return &Conn{
ExtendedConn: bufio.NewExtendedConn(conn),
writer: bufio.NewVectorisedWriter(conn),
request: Request{
UUID: uuid,
Command: command,
Destination: destination,
Flow: flow,
},
}
}
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.ExtendedConn)
if err != nil {
return
}
c.responseRead = true
}
return c.ExtendedConn.Read(b)
}
func (c *Conn) ReadBuffer(buffer *buf.Buffer) error {
if !c.responseRead {
err := ReadResponse(c.ExtendedConn)
if err != nil {
return err
}
c.responseRead = true
}
return c.ExtendedConn.ReadBuffer(buffer)
}
func (c *Conn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
err = WriteRequest(c.ExtendedConn, c.request, b)
if err == nil {
n = len(b)
}
c.requestWritten = true
return
}
return c.ExtendedConn.Write(b)
}
func (c *Conn) WriteBuffer(buffer *buf.Buffer) error {
if !c.requestWritten {
EncodeRequest(c.request, buf.With(buffer.ExtendHeader(RequestLen(c.request))))
c.requestWritten = true
}
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *Conn) WriteVectorised(buffers []*buf.Buffer) error {
if !c.requestWritten {
buffer := buf.NewSize(RequestLen(c.request))
EncodeRequest(c.request, buffer)
c.requestWritten = true
return c.writer.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...))
}
return c.writer.WriteVectorised(buffers)
}
func (c *Conn) ReaderReplaceable() bool {
return c.responseRead
}
func (c *Conn) WriterReplaceable() bool {
return c.requestWritten
}
func (c *Conn) NeedHandshake() bool { func (c *Conn) NeedHandshake() bool {
return !c.requestWritten return !c.requestWritten
} }
func (c *Conn) Read(b []byte) (n int, err error) { func (c *Conn) FrontHeadroom() int {
if !c.responseRead { if c.requestWritten {
err = ReadResponse(c.Conn) return 0
if err != nil {
return
}
c.responseRead = true
} }
return c.protocolConn.Read(b) return RequestLen(c.request)
}
func (c *Conn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
request := Request{c.key, c.command, c.destination, c.flow}
if c.protocolConn != nil {
err = WriteRequest(c.Conn, request, nil)
} else {
err = WriteRequest(c.Conn, request, b)
}
if err == nil {
n = len(b)
}
c.requestWritten = true
if c.protocolConn == nil {
return
}
}
return c.protocolConn.Write(b)
}
func (c *Conn) NeedAdditionalReadDeadline() bool {
return true
} }
func (c *Conn) Upstream() any { func (c *Conn) Upstream() any {
return c.Conn return c.ExtendedConn
} }
type PacketConn struct { type PacketConn struct {

View file

@ -11,10 +11,12 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03} tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03} tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
)
commandPaddingContinue byte = 0 const (
commandPaddingEnd byte = 1 commandPaddingContinue byte = iota
commandPaddingDirect byte = 2 commandPaddingEnd
commandPaddingDirect
) )
var tls13CipherSuiteDic = map[uint16]string{ var tls13CipherSuiteDic = map[uint16]string{

View file

@ -128,7 +128,7 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
requestLen += 1 // protobuf length requestLen += 1 // protobuf length
var addonsLen int var addonsLen int
if request.Command == vmess.CommandTCP && request.Flow != "" { if request.Flow != "" {
addonsLen += 1 // protobuf header addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow))) addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow) addonsLen += len(request.Flow)
@ -165,6 +165,62 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
return common.Error(writer.Write(buffer.Bytes())) return common.Error(writer.Write(buffer.Bytes()))
} }
func EncodeRequest(request Request, buffer *buf.Buffer) {
var requestLen int
requestLen += 1 // version
requestLen += 16 // uuid
requestLen += 1 // protobuf length
var addonsLen int
if request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow)
requestLen += addonsLen
}
requestLen += 1 // command
if request.Command != vmess.CommandMux {
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
}
common.Must(
buffer.WriteByte(Version),
common.Error(buffer.Write(request.UUID[:])),
buffer.WriteByte(byte(addonsLen)),
)
if addonsLen > 0 {
common.Must(buffer.WriteByte(10))
binary.PutUvarint(buffer.Extend(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
common.Must(common.Error(buffer.Write([]byte(request.Flow))))
}
common.Must(
buffer.WriteByte(request.Command),
)
if request.Command != vmess.CommandMux {
common.Must(vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination))
}
}
func RequestLen(request Request) int {
var requestLen int
requestLen += 1 // version
requestLen += 16 // uuid
requestLen += 1 // protobuf length
var addonsLen int
if request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow)
requestLen += addonsLen
}
requestLen += 1 // command
if request.Command != vmess.CommandMux {
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
}
return requestLen
}
func WritePacketRequest(writer io.Writer, request Request, payload []byte) error { func WritePacketRequest(writer io.Writer, request Request, payload []byte) error {
var requestLen int var requestLen int
requestLen += 1 // version requestLen += 1 // version

View file

@ -68,30 +68,32 @@ func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata
metadata.Destination = request.Destination metadata.Destination = request.Destination
userFlow := s.userFlow[user] userFlow := s.userFlow[user]
if request.Flow == FlowVision && request.Command == vmess.NetworkUDP {
var responseWriter io.Writer return E.New(FlowVision, " flow does not support UDP")
if request.Command == vmess.CommandTCP { } else if request.Flow != userFlow {
if request.Flow != userFlow { return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
}
switch userFlow {
case "":
case FlowVision:
responseWriter = conn
conn, err = NewVisionConn(conn, request.UUID, s.logger)
if err != nil {
return E.Cause(err, "initialize vision")
}
}
} }
if request.Command == vmess.CommandUDP {
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
}
responseConn := &serverConn{ExtendedConn: bufio.NewExtendedConn(conn), writer: bufio.NewVectorisedWriter(conn)}
switch userFlow {
case FlowVision:
conn, err = NewVisionConn(responseConn, conn, request.UUID, s.logger)
if err != nil {
return E.Cause(err, "initialize vision")
}
case "":
conn = responseConn
default:
return E.New("unknown flow: ", userFlow)
}
switch request.Command { switch request.Command {
case vmess.CommandTCP: case vmess.CommandTCP:
return s.handler.NewConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, metadata) return s.handler.NewConnection(ctx, conn, metadata)
case vmess.CommandUDP:
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
case vmess.CommandMux: case vmess.CommandMux:
return vmess.HandleMuxConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, s.handler) return vmess.HandleMuxConnection(ctx, conn, s.handler)
default: default:
return E.New("unknown command: ", request.Command) return E.New("unknown command: ", request.Command)
} }
@ -104,42 +106,70 @@ func flowName(value string) string {
return value return value
} }
var _ N.VectorisedWriter = (*serverConn)(nil)
type serverConn struct { type serverConn struct {
net.Conn N.ExtendedConn
responseWriter io.Writer writer N.VectorisedWriter
responseWritten bool responseWritten bool
} }
func (c *serverConn) Read(b []byte) (n int, err error) { func (c *serverConn) Read(b []byte) (n int, err error) {
return c.Conn.Read(b) return c.ExtendedConn.Read(b)
} }
func (c *serverConn) Write(b []byte) (n int, err error) { func (c *serverConn) Write(b []byte) (n int, err error) {
if !c.responseWritten { if !c.responseWritten {
if c.responseWriter == nil { _, err = bufio.WriteVectorised(c.writer, [][]byte{{Version, 0}, b})
_, err = bufio.WriteVectorised(bufio.NewVectorisedWriter(c.Conn), [][]byte{{Version, 0}, b}) if err == nil {
if err == nil { n = len(b)
n = len(b)
}
c.responseWritten = true
return
} else {
_, err = c.responseWriter.Write([]byte{Version, 0})
if err != nil {
return
}
c.responseWritten = true
} }
c.responseWritten = true
return
} }
return c.Conn.Write(b) return c.ExtendedConn.Write(b)
}
func (c *serverConn) WriteBuffer(buffer *buf.Buffer) error {
if !c.responseWritten {
header := buffer.ExtendHeader(2)
header[0] = Version
header[1] = 0
c.responseWritten = true
}
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *serverConn) WriteVectorised(buffers []*buf.Buffer) error {
if !c.responseWritten {
err := c.writer.WriteVectorised(append([]*buf.Buffer{buf.As([]byte{Version, 0})}, buffers...))
c.responseWritten = true
return err
}
return c.writer.WriteVectorised(buffers)
} }
func (c *serverConn) NeedAdditionalReadDeadline() bool { func (c *serverConn) NeedAdditionalReadDeadline() bool {
return true return true
} }
func (c *serverConn) FrontHeadroom() int {
if c.responseWritten {
return 0
}
return 2
}
func (c *serverConn) ReaderReplaceable() bool {
return true
}
func (c *serverConn) WriterReplaceable() bool {
return c.responseWritten
}
func (c *serverConn) Upstream() any { func (c *serverConn) Upstream() any {
return c.Conn return c.ExtendedConn
} }
type serverPacketConn struct { type serverPacketConn struct {

View file

@ -56,12 +56,12 @@ type VisionConn struct {
withinPaddingBuffers bool withinPaddingBuffers bool
remainingContent int remainingContent int
remainingPadding int remainingPadding int
currentCommand int currentCommand byte
directRead bool directRead bool
remainingReader io.Reader remainingReader io.Reader
} }
func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) { func NewVisionConn(conn net.Conn, tlsConn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
var ( var (
loaded bool loaded bool
reflectType reflect.Type reflectType reflect.Type
@ -69,7 +69,7 @@ func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*Vis
netConn net.Conn netConn net.Conn
) )
for _, tlsCreator := range tlsRegistry { for _, tlsCreator := range tlsRegistry {
loaded, netConn, reflectType, reflectPointer = tlsCreator(conn) loaded, netConn, reflectType, reflectPointer = tlsCreator(tlsConn)
if loaded { if loaded {
break break
} }
@ -103,6 +103,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
if c.remainingReader != nil { if c.remainingReader != nil {
n, err = c.remainingReader.Read(p) n, err = c.remainingReader.Read(p)
if err == io.EOF { if err == io.EOF {
err = nil
c.remainingReader = nil c.remainingReader = nil
} }
if n > 0 { if n > 0 {
@ -113,6 +114,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
return c.netConn.Read(p) return c.netConn.Read(p)
} }
var bufferBytes []byte var bufferBytes []byte
var chunkBuffer *buf.Buffer
if len(p) > xrayChunkSize { if len(p) > xrayChunkSize {
n, err = c.Conn.Read(p) n, err = c.Conn.Read(p)
if err != nil { if err != nil {
@ -120,21 +122,26 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
} }
bufferBytes = p[:n] bufferBytes = p[:n]
} else { } else {
buffer, err := c.reader.ReadChunk() chunkBuffer, err = c.reader.ReadChunk()
if err != nil { if err != nil {
return 0, err return 0, err
} }
defer buffer.FullReset() bufferBytes = chunkBuffer.Bytes()
bufferBytes = buffer.Bytes()
} }
if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 { if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 {
buffers := c.unPadding(bufferBytes) buffers := c.unPadding(bufferBytes)
if chunkBuffer != nil {
buffers = common.Map(buffers, func(it *buf.Buffer) *buf.Buffer {
return it.ToOwned()
})
chunkBuffer.FullReset()
}
if c.remainingContent == 0 && c.remainingPadding == 0 { if c.remainingContent == 0 && c.remainingPadding == 0 {
if c.currentCommand == 1 { if c.currentCommand == commandPaddingEnd {
c.withinPaddingBuffers = false c.withinPaddingBuffers = false
c.remainingContent = -1 c.remainingContent = -1
c.remainingPadding = -1 c.remainingPadding = -1
} else if c.currentCommand == 2 { } else if c.currentCommand == commandPaddingDirect {
c.withinPaddingBuffers = false c.withinPaddingBuffers = false
c.directRead = true c.directRead = true
@ -142,17 +149,17 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
buffers = append(buffers, inputBuffer) buffers = append(buffers, buf.As(inputBuffer))
rawInputBuffer, err := io.ReadAll(c.rawInput) rawInputBuffer, err := io.ReadAll(c.rawInput)
if err != nil { if err != nil {
return 0, err return 0, err
} }
buffers = append(buffers, rawInputBuffer) buffers = append(buffers, buf.As(rawInputBuffer))
c.logger.Trace("XtlsRead readV") c.logger.Trace("XtlsRead readV")
} else if c.currentCommand == 0 { } else if c.currentCommand == commandPaddingContinue {
c.withinPaddingBuffers = true c.withinPaddingBuffers = true
} else { } else {
return 0, E.New("unknown command ", c.currentCommand) return 0, E.New("unknown command ", c.currentCommand)
@ -163,14 +170,18 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
c.withinPaddingBuffers = false c.withinPaddingBuffers = false
} }
if c.numberOfPacketToFilter > 0 { if c.numberOfPacketToFilter > 0 {
c.filterTLS(buffers) c.filterTLS(buf.ToSliceMulti(buffers))
} }
c.remainingReader = io.MultiReader(common.Map(buffers, func(it []byte) io.Reader { return bytes.NewReader(it) })...) c.remainingReader = io.MultiReader(common.Map(buffers, func(it *buf.Buffer) io.Reader { return it })...)
return c.Read(p) return c.Read(p)
} else { } else {
if c.numberOfPacketToFilter > 0 { if c.numberOfPacketToFilter > 0 {
c.filterTLS([][]byte{bufferBytes}) c.filterTLS([][]byte{bufferBytes})
} }
if chunkBuffer != nil {
n = copy(p, bufferBytes)
chunkBuffer.Advance(n)
}
return return
} }
} }
@ -310,7 +321,7 @@ func (c *VisionConn) padding(buffer *buf.Buffer, command byte) *buf.Buffer {
return newBuffer return newBuffer
} }
func (c *VisionConn) unPadding(buffer []byte) [][]byte { func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
var bufferIndex int var bufferIndex int
if c.remainingContent == -1 && c.remainingPadding == -1 { if c.remainingContent == -1 && c.remainingPadding == -1 {
if len(buffer) >= 21 && bytes.Equal(c.userUUID[:], buffer[:16]) { if len(buffer) >= 21 && bytes.Equal(c.userUUID[:], buffer[:16]) {
@ -321,17 +332,17 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
} }
} }
if c.remainingContent == -1 && c.remainingPadding == -1 { if c.remainingContent == -1 && c.remainingPadding == -1 {
return [][]byte{buffer} return []*buf.Buffer{buf.As(buffer)}
} }
var buffers [][]byte var buffers []*buf.Buffer
for bufferIndex < len(buffer) { for bufferIndex < len(buffer) {
if c.remainingContent <= 0 && c.remainingPadding <= 0 { if c.remainingContent <= 0 && c.remainingPadding <= 0 {
if c.currentCommand == 1 { if c.currentCommand == 1 {
buffers = append(buffers, buffer[bufferIndex:]) buffers = append(buffers, buf.As(buffer[bufferIndex:]))
break break
} else { } else {
paddingInfo := buffer[bufferIndex : bufferIndex+5] paddingInfo := buffer[bufferIndex : bufferIndex+5]
c.currentCommand = int(paddingInfo[0]) c.currentCommand = paddingInfo[0]
c.remainingContent = int(paddingInfo[1])<<8 | int(paddingInfo[2]) c.remainingContent = int(paddingInfo[1])<<8 | int(paddingInfo[2])
c.remainingPadding = int(paddingInfo[3])<<8 | int(paddingInfo[4]) c.remainingPadding = int(paddingInfo[3])<<8 | int(paddingInfo[4])
bufferIndex += 5 bufferIndex += 5
@ -342,7 +353,7 @@ func (c *VisionConn) unPadding(buffer []byte) [][]byte {
if end > len(buffer)-bufferIndex { if end > len(buffer)-bufferIndex {
end = len(buffer) - bufferIndex end = len(buffer) - bufferIndex
} }
buffers = append(buffers, buffer[bufferIndex:bufferIndex+end]) buffers = append(buffers, buf.As(buffer[bufferIndex:bufferIndex+end]))
c.remainingContent -= end c.remainingContent -= end
bufferIndex += end bufferIndex += end
} else { } else {