diff --git a/common/tls/reality_client.go b/common/tls/reality_client.go index 1673749c..7742b5b4 100644 --- a/common/tls/reality_client.go +++ b/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[:]) diff --git a/test/reality_test.go b/test/reality_test.go index a3362b4d..b330fe16 100644 --- a/test/reality_test.go +++ b/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", }, }, }, diff --git a/transport/vless/client.go b/transport/vless/client.go index 76b4ffb1..14a4e4c8 100644 --- a/transport/vless/client.go +++ b/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 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 - } - c.responseRead = true +func (c *Conn) FrontHeadroom() int { + if c.requestWritten { + return 0 } - 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 { diff --git a/transport/vless/constant.go b/transport/vless/constant.go index 5602eef4..fb27af56 100644 --- a/transport/vless/constant.go +++ b/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{ diff --git a/transport/vless/protocol.go b/transport/vless/protocol.go index 60980d61..928c97ab 100644 --- a/transport/vless/protocol.go +++ b/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 diff --git a/transport/vless/service.go b/transport/vless/service.go index e31f0ae9..7b690202 100644 --- a/transport/vless/service.go +++ b/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] - - 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.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 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.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 { 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 { diff --git a/transport/vless/vision.go b/transport/vless/vision.go index cd323f5f..3851f6d5 100644 --- a/transport/vless/vision.go +++ b/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 {