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[1] = 8
hello.SessionId[2] = 0
hello.SessionId[2] = 1
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
copy(hello.SessionId[8:], e.shortID[:])

View file

@ -141,6 +141,95 @@ func TestVLESSVisionReality(t *testing.T) {
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) {
t.Run("grpc", func(t *testing.T) {
testVLESSRealityTransport(t, &option.V2RayTransportOptions{
@ -160,8 +249,6 @@ func TestVLESSRealityTransport(t *testing.T) {
}
func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
userUUID := newUUID()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
@ -206,52 +293,11 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
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{
{
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,
Tag: "vless-out",
@ -282,7 +328,7 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
{
DefaultOptions: option.DefaultRule{
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/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
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
}
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 {
vConn, err := NewVisionConn(conn, c.key, c.logger)
protocolConn, err := NewVisionConn(conn, tlsConn, c.key, c.logger)
if err != nil {
return nil, E.Cause(err, "initialize vision")
}
conn = vConn
conn = protocolConn
}
return conn, nil
}
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) {
vConn, err := c.prepareConn(conn)
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil {
return nil, err
}
serverConn := &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}
return serverConn, common.Error(serverConn.Write(nil))
return protocolConn, common.Error(remoteConn.Write(nil))
}
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (*Conn, error) {
vConn, err := c.prepareConn(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) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
return c.prepareConn(NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow), conn)
}
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) {
serverConn := &Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}
err := common.Error(serverConn.Write(nil))
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil {
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) {
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 {
net.Conn
protocolConn net.Conn
key [16]byte
command byte
destination M.Socksaddr
flow string
N.ExtendedConn
writer N.VectorisedWriter
request Request
requestWritten 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 {
return !c.requestWritten
}
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.Conn)
if err != nil {
return
func (c *Conn) FrontHeadroom() int {
if c.requestWritten {
return 0
}
c.responseRead = true
}
return c.protocolConn.Read(b)
}
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
return RequestLen(c.request)
}
func (c *Conn) Upstream() any {
return c.Conn
return c.ExtendedConn
}
type PacketConn struct {

View file

@ -11,10 +11,12 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
)
commandPaddingContinue byte = 0
commandPaddingEnd byte = 1
commandPaddingDirect byte = 2
const (
commandPaddingContinue byte = iota
commandPaddingEnd
commandPaddingDirect
)
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
var addonsLen int
if request.Command == vmess.CommandTCP && request.Flow != "" {
if request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(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()))
}
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 {
var requestLen int
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
userFlow := s.userFlow[user]
var responseWriter io.Writer
if request.Command == vmess.CommandTCP {
if request.Flow != userFlow {
if request.Flow == FlowVision && request.Command == vmess.NetworkUDP {
return E.New(FlowVision, " flow does not support UDP")
} else if request.Flow != userFlow {
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
}
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 "":
case FlowVision:
responseWriter = conn
conn, err = NewVisionConn(conn, request.UUID, s.logger)
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 {
case vmess.CommandTCP:
return s.handler.NewConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, metadata)
case vmess.CommandUDP:
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
return s.handler.NewConnection(ctx, conn, metadata)
case vmess.CommandMux:
return vmess.HandleMuxConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, s.handler)
return vmess.HandleMuxConnection(ctx, conn, s.handler)
default:
return E.New("unknown command: ", request.Command)
}
@ -104,42 +106,70 @@ func flowName(value string) string {
return value
}
var _ N.VectorisedWriter = (*serverConn)(nil)
type serverConn struct {
net.Conn
responseWriter io.Writer
N.ExtendedConn
writer N.VectorisedWriter
responseWritten bool
}
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) {
if !c.responseWritten {
if c.responseWriter == nil {
_, err = bufio.WriteVectorised(bufio.NewVectorisedWriter(c.Conn), [][]byte{{Version, 0}, b})
_, err = bufio.WriteVectorised(c.writer, [][]byte{{Version, 0}, b})
if err == nil {
n = len(b)
}
c.responseWritten = true
return
} else {
_, err = c.responseWriter.Write([]byte{Version, 0})
if err != nil {
return
}
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.Conn.Write(b)
return c.writer.WriteVectorised(buffers)
}
func (c *serverConn) NeedAdditionalReadDeadline() bool {
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 {
return c.Conn
return c.ExtendedConn
}
type serverPacketConn struct {

View file

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