|
|
|
@ -10,6 +10,7 @@ import (
|
|
|
|
|
"github.com/quic-go/quic-go/quicvarint" |
|
|
|
|
"github.com/xtls/xray-core/common" |
|
|
|
|
"github.com/xtls/xray-core/common/buf" |
|
|
|
|
"github.com/xtls/xray-core/common/bytespool" |
|
|
|
|
"github.com/xtls/xray-core/common/errors" |
|
|
|
|
ptls "github.com/xtls/xray-core/common/protocol/tls" |
|
|
|
|
"golang.org/x/crypto/hkdf" |
|
|
|
@ -141,7 +142,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
|
|
|
|
packetNumber = uint32(n) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if packetNumber != 0 { |
|
|
|
|
if packetNumber != 0 && packetNumber != 1 { |
|
|
|
|
return nil, errNotQuicInitial |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -159,32 +160,92 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
buffer = buf.FromBytes(decrypted) |
|
|
|
|
frameType, err := buffer.ReadByte() |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if frameType != 0x6 { |
|
|
|
|
// not crypto frame
|
|
|
|
|
return &SniffHeader{domain: ""}, nil |
|
|
|
|
} |
|
|
|
|
if common.Error2(quicvarint.Read(buffer)) != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
dataLen, err := quicvarint.Read(buffer) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if dataLen > uint64(buffer.Len()) { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
|
|
|
|
|
cryptoLen := uint(0) |
|
|
|
|
cryptoData := bytespool.Alloc(buffer.Len()) |
|
|
|
|
defer bytespool.Free(cryptoData) |
|
|
|
|
for i := 0; !buffer.IsEmpty(); i++ { |
|
|
|
|
frameType := byte(0x0) // Default to PADDING frame
|
|
|
|
|
for frameType == 0x0 && !buffer.IsEmpty() { |
|
|
|
|
frameType, _ = buffer.ReadByte() |
|
|
|
|
} |
|
|
|
|
switch frameType { |
|
|
|
|
case 0x00: // PADDING frame
|
|
|
|
|
case 0x01: // PING frame
|
|
|
|
|
case 0x02, 0x03: // ACK frame
|
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count
|
|
|
|
|
if err != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range
|
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if frameType == 0x03 { |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
case 0x06: // CRYPTO frame, we will use this frame
|
|
|
|
|
offset, err := quicvarint.Read(buffer) // Field: Offset
|
|
|
|
|
if err != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
length, err := quicvarint.Read(buffer) // Field: Length
|
|
|
|
|
if err != nil || length > uint64(buffer.Len()) { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if cryptoLen < uint(offset+length) { |
|
|
|
|
cryptoLen = uint(offset + length) |
|
|
|
|
} |
|
|
|
|
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
|
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length
|
|
|
|
|
if err != nil { |
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
if _, err := buffer.ReadBytes(int32(length)); err != nil { // Field: Reason Phrase
|
|
|
|
|
return nil, io.ErrUnexpectedEOF |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
// Only above frame types are permitted in initial packet.
|
|
|
|
|
// See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8
|
|
|
|
|
return nil, errNotQuicInitial |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
frameData, err := buffer.ReadBytes(int32(dataLen)) |
|
|
|
|
common.Must(err) |
|
|
|
|
|
|
|
|
|
tlsHdr := &ptls.SniffHeader{} |
|
|
|
|
err = ptls.ReadClientHello(frameData, tlsHdr) |
|
|
|
|
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return &SniffHeader{domain: tlsHdr.Domain()}, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|