Skip to content

Commit 8ceba34

Browse files
Vigilansxiaokangwangdyhkwong
authored
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 <[email protected]> * 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 <[email protected]> Co-authored-by: Shelikhoo <[email protected]> Co-authored-by: dyhkwong <[email protected]>
1 parent 807d4b2 commit 8ceba34

File tree

5 files changed

+446
-177
lines changed

5 files changed

+446
-177
lines changed

app/dispatcher/default.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,27 @@ type cachedReader struct {
3333
cache buf.MultiBuffer
3434
}
3535

36-
func (r *cachedReader) Cache(b *buf.Buffer) {
37-
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
36+
func (r *cachedReader) Cache(b *buf.Buffer) error {
37+
mb, err := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
38+
if err != nil {
39+
return err
40+
}
3841
r.Lock()
3942
if !mb.IsEmpty() {
4043
r.cache, _ = buf.MergeMulti(r.cache, mb)
4144
}
42-
b.Clear()
43-
rawBytes := b.Extend(buf.Size)
45+
cacheLen := r.cache.Len()
46+
if cacheLen <= b.Cap() {
47+
b.Clear()
48+
} else {
49+
b.Release()
50+
*b = *buf.NewWithSize(cacheLen)
51+
}
52+
rawBytes := b.Extend(cacheLen)
4453
n := r.cache.Copy(rawBytes)
4554
b.Resize(0, int32(n))
4655
r.Unlock()
56+
return nil
4757
}
4858

4959
func (r *cachedReader) readInternal() buf.MultiBuffer {
@@ -257,20 +267,24 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
257267
case <-ctx.Done():
258268
return nil, ctx.Err()
259269
default:
260-
totalAttempt++
261-
if totalAttempt > 2 {
262-
return nil, errSniffingTimeout
263-
}
270+
cacheErr := cReader.Cache(payload)
264271

265-
cReader.Cache(payload)
266272
if !payload.IsEmpty() {
267273
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
268-
if err != common.ErrNoClue {
274+
switch err {
275+
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
276+
totalAttempt++
277+
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
278+
if cacheErr != nil { // Cache error (e.g. timeout) counts for failed attempt
279+
totalAttempt++
280+
}
281+
default:
269282
return result, err
270283
}
271284
}
272-
if payload.IsFull() {
273-
return nil, errUnknownContent
285+
286+
if totalAttempt >= 2 {
287+
return nil, errSniffingTimeout
274288
}
275289
}
276290
}

app/dispatcher/sniffer.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/v2fly/v2ray-core/v5/common"
77
"github.com/v2fly/v2ray-core/v5/common/net"
8+
"github.com/v2fly/v2ray-core/v5/common/protocol"
89
"github.com/v2fly/v2ray-core/v5/common/protocol/bittorrent"
910
"github.com/v2fly/v2ray-core/v5/common/protocol/http"
1011
"github.com/v2fly/v2ray-core/v5/common/protocol/quic"
@@ -57,17 +58,20 @@ var errUnknownContent = newError("unknown content")
5758
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
5859
var pendingSniffer []protocolSnifferWithMetadata
5960
for _, si := range s.sniffer {
60-
s := si.protocolSniffer
61+
sniffer := si.protocolSniffer
6162
if si.metadataSniffer {
6263
continue
6364
}
6465
if si.network != network {
6566
continue
6667
}
67-
result, err := s(c, payload)
68+
result, err := sniffer(c, payload)
6869
if err == common.ErrNoClue {
6970
pendingSniffer = append(pendingSniffer, si)
7071
continue
72+
} else if err == protocol.ErrProtoNeedMoreData { // Sniffer protocol matched, but need more data to complete sniffing
73+
s.sniffer = []protocolSnifferWithMetadata{si}
74+
return nil, protocol.ErrProtoNeedMoreData
7175
}
7276

7377
if err == nil && result != nil {

common/protocol/protocol.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
package protocol
22

3+
import (
4+
"errors"
5+
)
6+
37
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
8+
9+
var ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing")

0 commit comments

Comments
 (0)