Skip to content

Commit 04d482f

Browse files
dyhkwongVigilans
authored andcommitted
Introduce protocol.ErrProtoNeedMoreData to allow sniffer to fetch more packets until complete
1 parent d5c5f6d commit 04d482f

File tree

5 files changed

+68
-44
lines changed

5 files changed

+68
-44
lines changed

app/dispatcher/default.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ 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)
@@ -50,6 +53,7 @@ func (r *cachedReader) Cache(b *buf.Buffer) {
5053
n := r.cache.Copy(rawBytes)
5154
b.Resize(0, int32(n))
5255
r.Unlock()
56+
return nil
5357
}
5458

5559
func (r *cachedReader) readInternal() buf.MultiBuffer {
@@ -263,20 +267,25 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
263267
case <-ctx.Done():
264268
return nil, ctx.Err()
265269
default:
266-
totalAttempt++
267-
if totalAttempt > 2 {
268-
return nil, errSniffingTimeout
269-
}
270+
cacheErr := cReader.Cache(payload)
270271

271-
cReader.Cache(payload)
272272
if !payload.IsEmpty() {
273273
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
274-
if err != common.ErrNoClue {
275-
return result, err
274+
if err == nil {
275+
return result, nil
276+
} else if err == common.ErrNoClue { // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
277+
totalAttempt++
278+
} else if err == protocol.ErrProtoNeedMoreData { // Protocol Need More Data: protocol matches, but need more data to complete sniffing
279+
if cacheErr != nil { // Cache error (e.g. timeout) counts for failed attempt
280+
totalAttempt++
281+
}
282+
} else {
283+
return nil, err
276284
}
277285
}
278-
if payload.IsFull() {
279-
return nil, errUnknownContent
286+
287+
if totalAttempt >= 2 {
288+
return nil, errSniffingTimeout
280289
}
281290
}
282291
}

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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
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 (
10+
ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing")
11+
)

common/protocol/quic/sniff.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/v2fly/v2ray-core/v5/common/buf"
1515
"github.com/v2fly/v2ray-core/v5/common/bytespool"
1616
"github.com/v2fly/v2ray-core/v5/common/errors"
17+
"github.com/v2fly/v2ray-core/v5/common/protocol"
1718
ptls "github.com/v2fly/v2ray-core/v5/common/protocol/tls"
1819
)
1920

@@ -267,7 +268,8 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
267268
}
268269
return &SniffHeader{domain: tlsHdr.Domain()}, nil
269270
}
270-
return nil, common.ErrNoClue
271+
// All payload is parsed as valid QUIC packets, but we need more packets for crypto data to read client hello.
272+
return nil, protocol.ErrProtoNeedMoreData
271273
}
272274

273275
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {

0 commit comments

Comments
 (0)