mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-07-05 16:38:17 -04:00
QUIC sniffer restructure (#3360)
This commit is contained in:
parent
77d2d1b172
commit
c8c1120747
@ -33,8 +33,8 @@ type cachedReader struct {
|
|||||||
cache buf.MultiBuffer
|
cache buf.MultiBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *cachedReader) Cache(b *buf.Buffer) error {
|
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
||||||
mb, err := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -42,14 +42,8 @@ func (r *cachedReader) Cache(b *buf.Buffer) error {
|
|||||||
if !mb.IsEmpty() {
|
if !mb.IsEmpty() {
|
||||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||||
}
|
}
|
||||||
cacheLen := r.cache.Len()
|
b.Clear()
|
||||||
if cacheLen <= b.Cap() {
|
rawBytes := b.Extend(b.Cap())
|
||||||
b.Clear()
|
|
||||||
} else {
|
|
||||||
b.Release()
|
|
||||||
*b = *buf.NewWithSize(cacheLen)
|
|
||||||
}
|
|
||||||
rawBytes := b.Extend(cacheLen)
|
|
||||||
n := r.cache.Copy(rawBytes)
|
n := r.cache.Copy(rawBytes)
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
r.Unlock()
|
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) {
|
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
||||||
payload := buf.New()
|
payload := buf.NewWithSize(32767)
|
||||||
|
|
||||||
defer func() {
|
defer payload.Release()
|
||||||
payload.Release()
|
|
||||||
}()
|
|
||||||
|
|
||||||
sniffer := NewSniffer(ctx)
|
sniffer := NewSniffer(ctx)
|
||||||
|
|
||||||
@ -264,13 +256,17 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentResult, contentErr := func() (SniffResult, error) {
|
contentResult, contentErr := func() (SniffResult, error) {
|
||||||
|
cacheDeadline := 200 * time.Millisecond
|
||||||
totalAttempt := 0
|
totalAttempt := 0
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
default:
|
default:
|
||||||
cacheErr := cReader.Cache(payload)
|
cachingStartingTimeStamp := time.Now()
|
||||||
|
cacheErr := cReader.Cache(payload, cacheDeadline)
|
||||||
|
cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
|
||||||
|
cacheDeadline -= cachingTimeElapsed
|
||||||
|
|
||||||
if !payload.IsEmpty() {
|
if !payload.IsEmpty() {
|
||||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
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
|
return nil, errSniffingTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common"
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/buf"
|
"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/errors"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/protocol"
|
"github.com/v2fly/v2ray-core/v5/common/protocol"
|
||||||
ptls "github.com/v2fly/v2ray-core/v5/common/protocol/tls"
|
ptls "github.com/v2fly/v2ray-core/v5/common/protocol/tls"
|
||||||
@ -49,12 +48,14 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SniffQUIC(b []byte) (*SniffHeader, error) {
|
func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil, common.ErrNoClue
|
||||||
|
}
|
||||||
|
|
||||||
// Crypto data separated across packets
|
// Crypto data separated across packets
|
||||||
cryptoLen := 0
|
cryptoLen := 0
|
||||||
cryptoData := bytespool.Alloc(int32(len(b)))
|
cryptoDataBuf := buf.NewWithSize(32767)
|
||||||
defer func() {
|
defer cryptoDataBuf.Release()
|
||||||
bytespool.Free(cryptoData)
|
|
||||||
}()
|
|
||||||
|
|
||||||
cache := buf.New()
|
cache := buf.New()
|
||||||
defer cache.Release()
|
defer cache.Release()
|
||||||
@ -230,14 +231,14 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
|||||||
}
|
}
|
||||||
if cryptoLen < int(offset+length) {
|
if cryptoLen < int(offset+length) {
|
||||||
cryptoLen = int(offset + length)
|
cryptoLen = int(offset + length)
|
||||||
if len(cryptoData) < cryptoLen {
|
if cryptoDataBuf.Cap() < int32(cryptoLen) {
|
||||||
newCryptoData := bytespool.Alloc(int32(cryptoLen))
|
return nil, io.ErrShortBuffer
|
||||||
copy(newCryptoData, cryptoData)
|
}
|
||||||
bytespool.Free(cryptoData)
|
if cryptoDataBuf.Len() != int32(cryptoLen) {
|
||||||
cryptoData = newCryptoData
|
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
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
|
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{}
|
tlsHdr := &ptls.SniffHeader{}
|
||||||
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
|
err = ptls.ReadClientHello(cryptoDataBuf.BytesRange(0, int32(cryptoLen)), tlsHdr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// The crypto data may have not been fully recovered in current packets,
|
// The crypto data may have not been fully recovered in current packets,
|
||||||
// So we continue to sniff rest packets.
|
// So we continue to sniff rest packets.
|
||||||
@ -271,6 +272,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
|||||||
}
|
}
|
||||||
return &SniffHeader{domain: tlsHdr.Domain()}, nil
|
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.
|
// All payload is parsed as valid QUIC packets, but we need more packets for crypto data to read client hello.
|
||||||
return nil, protocol.ErrProtoNeedMoreData
|
return nil, protocol.ErrProtoNeedMoreData
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user