浏览代码

QUIC sniffer restructure (#3360)

Xiaokang Wang (Shelikhoo) 6 月之前
父节点
当前提交
c8c1120747
共有 2 个文件被更改,包括 26 次插入28 次删除
  1. 12 16
      app/dispatcher/default.go
  2. 14 12
      common/protocol/quic/sniff.go

+ 12 - 16
app/dispatcher/default.go

@@ -33,8 +33,8 @@ type cachedReader struct {
 	cache  buf.MultiBuffer
 }
 
-func (r *cachedReader) Cache(b *buf.Buffer) error {
-	mb, err := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
+func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
+	mb, err := r.reader.ReadMultiBufferTimeout(deadline)
 	if err != nil {
 		return err
 	}
@@ -42,14 +42,8 @@ func (r *cachedReader) Cache(b *buf.Buffer) error {
 	if !mb.IsEmpty() {
 		r.cache, _ = buf.MergeMulti(r.cache, mb)
 	}
-	cacheLen := r.cache.Len()
-	if cacheLen <= b.Cap() {
-		b.Clear()
-	} else {
-		b.Release()
-		*b = *buf.NewWithSize(cacheLen)
-	}
-	rawBytes := b.Extend(cacheLen)
+	b.Clear()
+	rawBytes := b.Extend(b.Cap())
 	n := r.cache.Copy(rawBytes)
 	b.Resize(0, int32(n))
 	r.Unlock()
@@ -249,11 +243,9 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
 }
 
 func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
-	payload := buf.New()
+	payload := buf.NewWithSize(32767)
 
-	defer func() {
-		payload.Release()
-	}()
+	defer payload.Release()
 
 	sniffer := NewSniffer(ctx)
 
@@ -264,13 +256,17 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
 	}
 
 	contentResult, contentErr := func() (SniffResult, error) {
+		cacheDeadline := 200 * time.Millisecond
 		totalAttempt := 0
 		for {
 			select {
 			case <-ctx.Done():
 				return nil, ctx.Err()
 			default:
-				cacheErr := cReader.Cache(payload)
+				cachingStartingTimeStamp := time.Now()
+				cacheErr := cReader.Cache(payload, cacheDeadline)
+				cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
+				cacheDeadline -= cachingTimeElapsed
 
 				if !payload.IsEmpty() {
 					result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
@@ -286,7 +282,7 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
 					}
 				}
 
-				if totalAttempt >= 2 {
+				if totalAttempt >= 2 || cacheDeadline <= 0 {
 					return nil, errSniffingTimeout
 				}
 			}

+ 14 - 12
common/protocol/quic/sniff.go

@@ -12,7 +12,6 @@ import (
 
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common/buf"
-	"github.com/v2fly/v2ray-core/v5/common/bytespool"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
 	"github.com/v2fly/v2ray-core/v5/common/protocol"
 	ptls "github.com/v2fly/v2ray-core/v5/common/protocol/tls"
@@ -49,12 +48,14 @@ var (
 )
 
 func SniffQUIC(b []byte) (*SniffHeader, error) {
+	if len(b) == 0 {
+		return nil, common.ErrNoClue
+	}
+
 	// Crypto data separated across packets
 	cryptoLen := 0
-	cryptoData := bytespool.Alloc(int32(len(b)))
-	defer func() {
-		bytespool.Free(cryptoData)
-	}()
+	cryptoDataBuf := buf.NewWithSize(32767)
+	defer cryptoDataBuf.Release()
 
 	cache := buf.New()
 	defer cache.Release()
@@ -230,14 +231,14 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
 				}
 				if cryptoLen < int(offset+length) {
 					cryptoLen = int(offset + length)
-					if len(cryptoData) < cryptoLen {
-						newCryptoData := bytespool.Alloc(int32(cryptoLen))
-						copy(newCryptoData, cryptoData)
-						bytespool.Free(cryptoData)
-						cryptoData = newCryptoData
+					if cryptoDataBuf.Cap() < int32(cryptoLen) {
+						return nil, io.ErrShortBuffer
+					}
+					if cryptoDataBuf.Len() != int32(cryptoLen) {
+						cryptoDataBuf.Extend(int32(cryptoLen) - cryptoDataBuf.Len())
 					}
 				}
-				if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
+				if _, err := buffer.Read(cryptoDataBuf.BytesRange(int32(offset), int32(offset+length))); err != nil { // Field: Crypto Data
 					return nil, io.ErrUnexpectedEOF
 				}
 			case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
@@ -262,7 +263,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
 		}
 
 		tlsHdr := &ptls.SniffHeader{}
-		err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
+		err = ptls.ReadClientHello(cryptoDataBuf.BytesRange(0, int32(cryptoLen)), tlsHdr)
 		if err != nil {
 			// The crypto data may have not been fully recovered in current packets,
 			// So we continue to sniff rest packets.
@@ -271,6 +272,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
 		}
 		return &SniffHeader{domain: tlsHdr.Domain()}, nil
 	}
+
 	// All payload is parsed as valid QUIC packets, but we need more packets for crypto data to read client hello.
 	return nil, protocol.ErrProtoNeedMoreData
 }