mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-05-04 03:29:08 -04:00
Correctly implement QUIC sniffer when handling multiple initial packets (#3310)
* Correctly implement QUIC sniffer when handling multiple initial packets * Only parse token for initial packet Signed-off-by: Vigilans <vigilans@foxmail.com> * Update test case for QUIC sniffer * Fix testcases * Third packet in `Handshake[2]; packet 1-3` mistakenly copied UDP header into payload, making the payload length 1278 instead of 1250 * Introduce `protocol.ErrProtoNeedMoreData` to allow sniffer to fetch more packets until complete --------- Signed-off-by: Vigilans <vigilans@foxmail.com> Co-authored-by: Shelikhoo <xiaokangwang@outlook.com> Co-authored-by: dyhkwong <50692134+dyhkwong@users.noreply.github.com>
This commit is contained in:
@@ -33,17 +33,27 @@ type cachedReader struct {
|
||||
cache buf.MultiBuffer
|
||||
}
|
||||
|
||||
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
||||
func (r *cachedReader) Cache(b *buf.Buffer) error {
|
||||
mb, err := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Lock()
|
||||
if !mb.IsEmpty() {
|
||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||
}
|
||||
b.Clear()
|
||||
rawBytes := b.Extend(buf.Size)
|
||||
cacheLen := r.cache.Len()
|
||||
if cacheLen <= b.Cap() {
|
||||
b.Clear()
|
||||
} else {
|
||||
b.Release()
|
||||
*b = *buf.NewWithSize(cacheLen)
|
||||
}
|
||||
rawBytes := b.Extend(cacheLen)
|
||||
n := r.cache.Copy(rawBytes)
|
||||
b.Resize(0, int32(n))
|
||||
r.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
||||
@@ -257,20 +267,24 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
cacheErr := cReader.Cache(payload)
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
||||
if err != common.ErrNoClue {
|
||||
switch err {
|
||||
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
|
||||
totalAttempt++
|
||||
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
|
||||
if cacheErr != nil { // Cache error (e.g. timeout) counts for failed attempt
|
||||
totalAttempt++
|
||||
}
|
||||
default:
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
|
||||
if totalAttempt >= 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/v2fly/v2ray-core/v5/common"
|
||||
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||
"github.com/v2fly/v2ray-core/v5/common/protocol"
|
||||
"github.com/v2fly/v2ray-core/v5/common/protocol/bittorrent"
|
||||
"github.com/v2fly/v2ray-core/v5/common/protocol/http"
|
||||
"github.com/v2fly/v2ray-core/v5/common/protocol/quic"
|
||||
@@ -57,17 +58,20 @@ var errUnknownContent = newError("unknown content")
|
||||
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
for _, si := range s.sniffer {
|
||||
s := si.protocolSniffer
|
||||
sniffer := si.protocolSniffer
|
||||
if si.metadataSniffer {
|
||||
continue
|
||||
}
|
||||
if si.network != network {
|
||||
continue
|
||||
}
|
||||
result, err := s(c, payload)
|
||||
result, err := sniffer(c, payload)
|
||||
if err == common.ErrNoClue {
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
} else if err == protocol.ErrProtoNeedMoreData { // Sniffer protocol matched, but need more data to complete sniffing
|
||||
s.sniffer = []protocolSnifferWithMetadata{si}
|
||||
return nil, protocol.ErrProtoNeedMoreData
|
||||
}
|
||||
|
||||
if err == nil && result != nil {
|
||||
|
||||
Reference in New Issue
Block a user