Skip to content

Commit 039e5f2

Browse files
Vigilansyuhan6665
authored andcommitted
Correctly implement quic sniffer's frame parsing
1 parent 242f3b0 commit 039e5f2

File tree

1 file changed

+83
-22
lines changed

1 file changed

+83
-22
lines changed

common/protocol/quic/sniff.go

+83-22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/quic-go/quic-go/quicvarint"
1111
"github.com/xtls/xray-core/common"
1212
"github.com/xtls/xray-core/common/buf"
13+
"github.com/xtls/xray-core/common/bytespool"
1314
"github.com/xtls/xray-core/common/errors"
1415
ptls "github.com/xtls/xray-core/common/protocol/tls"
1516
"golang.org/x/crypto/hkdf"
@@ -141,7 +142,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
141142
packetNumber = uint32(n)
142143
}
143144

144-
if packetNumber != 0 {
145+
if packetNumber != 0 && packetNumber != 1 {
145146
return nil, errNotQuicInitial
146147
}
147148

@@ -159,32 +160,92 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
159160
return nil, err
160161
}
161162
buffer = buf.FromBytes(decrypted)
162-
frameType, err := buffer.ReadByte()
163-
if err != nil {
164-
return nil, io.ErrUnexpectedEOF
165-
}
166-
if frameType != 0x6 {
167-
// not crypto frame
168-
return &SniffHeader{domain: ""}, nil
169-
}
170-
if common.Error2(quicvarint.Read(buffer)) != nil {
171-
return nil, io.ErrUnexpectedEOF
172-
}
173-
dataLen, err := quicvarint.Read(buffer)
174-
if err != nil {
175-
return nil, io.ErrUnexpectedEOF
176-
}
177-
if dataLen > uint64(buffer.Len()) {
178-
return nil, io.ErrUnexpectedEOF
163+
164+
cryptoLen := uint(0)
165+
cryptoData := bytespool.Alloc(buffer.Len())
166+
defer bytespool.Free(cryptoData)
167+
for i := 0; !buffer.IsEmpty(); i++ {
168+
frameType := byte(0x0) // Default to PADDING frame
169+
for frameType == 0x0 && !buffer.IsEmpty() {
170+
frameType, _ = buffer.ReadByte()
171+
}
172+
switch frameType {
173+
case 0x00: // PADDING frame
174+
case 0x01: // PING frame
175+
case 0x02, 0x03: // ACK frame
176+
if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged
177+
return nil, io.ErrUnexpectedEOF
178+
}
179+
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay
180+
return nil, io.ErrUnexpectedEOF
181+
}
182+
ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count
183+
if err != nil {
184+
return nil, io.ErrUnexpectedEOF
185+
}
186+
if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range
187+
return nil, io.ErrUnexpectedEOF
188+
}
189+
for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range
190+
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap
191+
return nil, io.ErrUnexpectedEOF
192+
}
193+
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length
194+
return nil, io.ErrUnexpectedEOF
195+
}
196+
}
197+
if frameType == 0x03 {
198+
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count
199+
return nil, io.ErrUnexpectedEOF
200+
}
201+
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count
202+
return nil, io.ErrUnexpectedEOF
203+
}
204+
if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count
205+
return nil, io.ErrUnexpectedEOF
206+
}
207+
}
208+
case 0x06: // CRYPTO frame, we will use this frame
209+
offset, err := quicvarint.Read(buffer) // Field: Offset
210+
if err != nil {
211+
return nil, io.ErrUnexpectedEOF
212+
}
213+
length, err := quicvarint.Read(buffer) // Field: Length
214+
if err != nil || length > uint64(buffer.Len()) {
215+
return nil, io.ErrUnexpectedEOF
216+
}
217+
if cryptoLen < uint(offset+length) {
218+
cryptoLen = uint(offset + length)
219+
}
220+
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
221+
return nil, io.ErrUnexpectedEOF
222+
}
223+
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
224+
if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code
225+
return nil, io.ErrUnexpectedEOF
226+
}
227+
if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type
228+
return nil, io.ErrUnexpectedEOF
229+
}
230+
length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length
231+
if err != nil {
232+
return nil, io.ErrUnexpectedEOF
233+
}
234+
if _, err := buffer.ReadBytes(int32(length)); err != nil { // Field: Reason Phrase
235+
return nil, io.ErrUnexpectedEOF
236+
}
237+
default:
238+
// Only above frame types are permitted in initial packet.
239+
// See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8
240+
return nil, errNotQuicInitial
241+
}
179242
}
180-
frameData, err := buffer.ReadBytes(int32(dataLen))
181-
common.Must(err)
243+
182244
tlsHdr := &ptls.SniffHeader{}
183-
err = ptls.ReadClientHello(frameData, tlsHdr)
245+
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
184246
if err != nil {
185247
return nil, err
186248
}
187-
188249
return &SniffHeader{domain: tlsHdr.Domain()}, nil
189250
}
190251

0 commit comments

Comments
 (0)