1
0
世界 2 жил өмнө
parent
commit
8eb7dd0059

+ 1 - 1
common/tls/reality_client.go

@@ -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[:])
 

+ 90 - 44
test/reality_test.go

@@ -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",
 					},
 				},
 			},

+ 89 - 41
transport/vless/client.go

@@ -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 (c *Conn) NeedHandshake() bool {
-	return !c.requestWritten
+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.Conn)
+		err = ReadResponse(c.ExtendedConn)
 		if err != nil {
 			return
 		}
 		c.responseRead = true
 	}
-	return c.protocolConn.Read(b)
+	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 {
-		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)
-		}
+		err = WriteRequest(c.ExtendedConn, c.request, b)
 		if err == nil {
 			n = len(b)
 		}
 		c.requestWritten = true
-		if c.protocolConn == nil {
-			return
-		}
+		return
 	}
-	return c.protocolConn.Write(b)
+	return c.ExtendedConn.Write(b)
 }
 
-func (c *Conn) NeedAdditionalReadDeadline() bool {
-	return true
+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) FrontHeadroom() int {
+	if c.requestWritten {
+		return 0
+	}
+	return RequestLen(c.request)
 }
 
 func (c *Conn) Upstream() any {
-	return c.Conn
+	return c.ExtendedConn
 }
 
 type PacketConn struct {

+ 5 - 3
transport/vless/constant.go

@@ -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{

+ 57 - 1
transport/vless/protocol.go

@@ -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

+ 66 - 36
transport/vless/service.go

@@ -68,30 +68,32 @@ func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata
 	metadata.Destination = request.Destination
 
 	userFlow := s.userFlow[user]
+	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))
+	}
 
-	var responseWriter io.Writer
-	if request.Command == vmess.CommandTCP {
-		if request.Flow != userFlow {
-			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 {
 	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})
-			if err == nil {
-				n = len(b)
-			}
-			c.responseWritten = true
-			return
-		} else {
-			_, err = c.responseWriter.Write([]byte{Version, 0})
-			if err != nil {
-				return
-			}
-			c.responseWritten = true
+		_, err = bufio.WriteVectorised(c.writer, [][]byte{{Version, 0}, b})
+		if err == nil {
+			n = len(b)
 		}
+		c.responseWritten = true
+		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 {

+ 30 - 19
transport/vless/vision.go

@@ -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 {