• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.06
/rust/src/quic/parser.rs
1
/* Copyright (C) 2021 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
use super::error::QuicError;
18
use super::frames::Frame;
19
use nom8::bytes::complete::take;
20
use nom8::combinator::map;
21
use nom8::number::complete::{be_u24, be_u32, be_u8};
22
use nom8::{IResult, Parser};
23
use std::convert::TryFrom;
24

25
/*
26
   gQUIC is the Google version of QUIC.
27

28
   The following docs were referenced when writing this parser
29

30
   References:
31
       - https://docs.google.com/document/d/1WJvyZflAO2pq77yOLbp9NsGjC1CHetAXV8I0fQe-B_U/edit
32
       - https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit
33
       - https://www.slideshare.net/shigeki_ohtsu/quic-overview
34
       - https://tools.ietf.org/html/draft-ietf-quic-transport-17#section-19.8
35
       - https://github.com/salesforce/GQUIC_Protocol_Analyzer/blob/master/src/gquic-protocol.pac
36
*/
37

38
// List of accepted and tested quic versions format
39
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
40
pub struct QuicVersion(pub u32);
41

42
impl QuicVersion {
43
    pub const Q043: QuicVersion = QuicVersion(0x51303433);
44
    pub const Q044: QuicVersion = QuicVersion(0x51303434);
45
    pub const Q045: QuicVersion = QuicVersion(0x51303435);
46
    pub const Q046: QuicVersion = QuicVersion(0x51303436);
47
    pub const V2: QuicVersion = QuicVersion(0x6b3343cf);
48

49
    fn is_gquic(&self) -> bool {
4,634✔
50
        *self == QuicVersion::Q043
4,634✔
51
            || *self == QuicVersion::Q044
4,615✔
52
            || *self == QuicVersion::Q045
4,609✔
53
            || *self == QuicVersion::Q046
4,601✔
54
    }
4,634✔
55
}
56

57
impl From<QuicVersion> for String {
58
    fn from(from: QuicVersion) -> Self {
296✔
59
        match from {
296✔
60
            QuicVersion(0x51303339) => "Q039".to_string(),
×
UNCOV
61
            QuicVersion(0x51303433) => "Q043".to_string(),
×
62
            QuicVersion(0x51303434) => "Q044".to_string(),
×
63
            QuicVersion(0x51303435) => "Q045".to_string(),
×
64
            QuicVersion(0x51303436) => "Q046".to_string(),
189✔
65
            QuicVersion(0x6b3343cf) => "v2".to_string(),
68✔
66
            QuicVersion(x) => format!("{:x}", x),
39✔
67
        }
68
    }
296✔
69
}
70
impl From<QuicVersion> for u32 {
71
    fn from(from: QuicVersion) -> Self {
461✔
72
        from.0
461✔
73
    }
461✔
74
}
75

76
impl From<u32> for QuicVersion {
77
    fn from(from: u32) -> Self {
×
78
        QuicVersion(from)
×
79
    }
×
80
}
81

82
#[derive(Debug, PartialEq, Eq)]
83
pub enum QuicType {
84
    Initial,
85
    Retry,
86
    Handshake,
87
    ZeroRTT,
88
    VersionNegotiation,
89
    Short,
90
}
91

92
const QUIC_FLAG_MULTIPATH: u8 = 0x40;
93
const QUIC_FLAG_DCID_LEN: u8 = 0x8;
94
const QUIC_FLAG_NONCE: u8 = 0x4;
95
const QUIC_FLAG_VERSION: u8 = 0x1;
96

97
#[derive(Debug, PartialEq, Eq)]
98
pub struct PublicFlags {
99
    pub is_long: bool,
100
    pub raw: u8,
101
}
102

103
impl PublicFlags {
104
    pub fn new(value: u8) -> Self {
2,394✔
105
        let is_long = value & 0x80 == 0x80;
2,394✔
106
        let raw = value;
2,394✔
107

2,394✔
108
        PublicFlags { is_long, raw }
2,394✔
109
    }
2,394✔
110
}
111

112
pub fn quic_pkt_num(input: &[u8]) -> u64 {
335✔
113
    // There must be a more idiomatic way sigh...
335✔
114
    match input.len() {
335✔
115
        1 => {
116
            return input[0] as u64;
244✔
117
        }
118
        2 => {
119
            return ((input[0] as u64) << 8) | (input[1] as u64);
51✔
120
        }
121
        3 => {
122
            return ((input[0] as u64) << 16) | ((input[1] as u64) << 8) | (input[2] as u64);
13✔
123
        }
124
        4 => {
125
            return ((input[0] as u64) << 24)
27✔
126
                | ((input[1] as u64) << 16)
27✔
127
                | ((input[2] as u64) << 8)
27✔
128
                | (input[3] as u64);
27✔
129
        }
130
        _ => {
131
            // should not be reachable
132
            debug_validate_fail!("Unexpected length for quic pkt num");
133
            return 0;
×
134
        }
135
    }
136
}
335✔
137

138
pub fn quic_var_uint(input: &[u8]) -> IResult<&[u8], u64, QuicError> {
16,217✔
139
    let (rest, first) = be_u8(input)?;
16,217✔
140
    let msb = first >> 6;
16,197✔
141
    let lsb = (first & 0x3F) as u64;
16,197✔
142
    match msb {
16,197✔
143
        3 => {
144
            // nom does not have be_u56
145
            let (rest, second) = be_u24(rest)?;
629✔
146
            let (rest, third) = be_u32(rest)?;
626✔
147
            return Ok((rest, (lsb << 56) | ((second as u64) << 32) | (third as u64)));
617✔
148
        }
149
        2 => {
150
            let (rest, second) = be_u24(rest)?;
666✔
151
            return Ok((rest, (lsb << 24) | (second as u64)));
660✔
152
        }
153
        1 => {
154
            let (rest, second) = be_u8(rest)?;
4,643✔
155
            return Ok((rest, (lsb << 8) | (second as u64)));
4,640✔
156
        }
157
        _ => {
158
            // only remaining case is msb==0
159
            return Ok((rest, lsb));
10,259✔
160
        }
161
    }
162
}
16,217✔
163

164
/// A QUIC packet's header.
165
#[derive(Debug, PartialEq, Eq)]
166
pub struct QuicHeader {
167
    pub flags: PublicFlags,
168
    pub ty: QuicType,
169
    pub version: QuicVersion,
170
    pub version_buf: Vec<u8>,
171
    pub dcid: Vec<u8>,
172
    pub scid: Vec<u8>,
173
    pub length: u16,
174
}
175

176
#[derive(Debug, PartialEq)]
177
pub(crate) struct QuicData {
178
    pub frames: Vec<Frame>,
179
}
180

181
impl QuicHeader {
182
    #[cfg(test)]
183
    pub(crate) fn new(
184
        flags: PublicFlags, ty: QuicType, version: QuicVersion, dcid: Vec<u8>, scid: Vec<u8>,
185
    ) -> Self {
186
        Self {
187
            flags,
188
            ty,
189
            version,
190
            version_buf: Vec::new(),
191
            dcid,
192
            scid,
193
            length: 0,
194
        }
195
    }
196

197
    pub(crate) fn from_bytes(
2,402✔
198
        input: &[u8], _dcid_len: usize,
2,402✔
199
    ) -> IResult<&[u8], QuicHeader, QuicError> {
2,402✔
200
        let (rest, first) = be_u8(input)?;
2,402✔
201
        let flags = PublicFlags::new(first);
2,394✔
202

2,394✔
203
        if !flags.is_long && (flags.raw & QUIC_FLAG_MULTIPATH) == 0 {
2,394✔
204
            let (mut rest, dcid) = if (flags.raw & QUIC_FLAG_DCID_LEN) != 0 {
128✔
205
                take(8_usize)(rest)?
31✔
206
            } else {
207
                take(0_usize)(rest)?
97✔
208
            };
209
            if (flags.raw & QUIC_FLAG_NONCE) != 0 && (flags.raw & QUIC_FLAG_DCID_LEN) == 0 {
126✔
210
                let (rest1, _) = take(32_usize)(rest)?;
16✔
211
                rest = rest1;
13✔
212
            }
110✔
213
            let version_buf: &[u8];
214
            let version;
215
            if (flags.raw & QUIC_FLAG_VERSION) != 0 {
123✔
216
                let (_, version_buf1) = take(4_usize)(rest)?;
28✔
217
                let (rest1, version1) = map(be_u32, QuicVersion).parse(rest)?;
24✔
218
                rest = rest1;
24✔
219
                version = version1;
24✔
220
                version_buf = version_buf1;
24✔
221
            } else {
95✔
222
                version = QuicVersion(0);
95✔
223
                version_buf = &rest[..0];
95✔
224
            }
95✔
225
            let pkt_num_len = 1 + ((flags.raw & 0x30) >> 4);
119✔
226
            let (mut rest, _pkt_num) = take(pkt_num_len)(rest)?;
119✔
227
            if (flags.raw & QUIC_FLAG_DCID_LEN) != 0 {
115✔
228
                let (rest1, _msg_auth_hash) = take(12_usize)(rest)?;
28✔
229
                rest = rest1;
26✔
230
            }
87✔
231
            let ty = if (flags.raw & QUIC_FLAG_VERSION) != 0 {
113✔
232
                QuicType::Initial
22✔
233
            } else {
234
                QuicType::Short
91✔
235
            };
236
            if let Ok(plength) = u16::try_from(rest.len()) {
113✔
237
                return Ok((
109✔
238
                    rest,
109✔
239
                    QuicHeader {
109✔
240
                        flags,
109✔
241
                        ty,
109✔
242
                        version,
109✔
243
                        version_buf: version_buf.to_vec(),
109✔
244
                        dcid: dcid.to_vec(),
109✔
245
                        scid: Vec::new(),
109✔
246
                        length: plength,
109✔
247
                    },
109✔
248
                ));
109✔
249
            } else {
250
                return Err(nom8::Err::Error(QuicError::InvalidPacket));
4✔
251
            }
252
        } else if !flags.is_long {
2,266✔
253
            // Decode short header
254
            // depends on version let (rest, dcid) = take(_dcid_len)(rest)?;
255

256
            if let Ok(plength) = u16::try_from(rest.len()) {
571✔
257
                return Ok((
570✔
258
                    rest,
570✔
259
                    QuicHeader {
570✔
260
                        flags,
570✔
261
                        ty: QuicType::Short,
570✔
262
                        version: QuicVersion(0),
570✔
263
                        version_buf: Vec::new(),
570✔
264
                        dcid: Vec::new(),
570✔
265
                        scid: Vec::new(),
570✔
266
                        length: plength,
570✔
267
                    },
570✔
268
                ));
570✔
269
            } else {
270
                return Err(nom8::Err::Error(QuicError::InvalidPacket));
1✔
271
            }
272
        } else {
273
            // Decode Long header
274
            let (_, version_buf) = take(4_usize)(rest)?;
1,695✔
275
            let (rest, version) = map(be_u32, QuicVersion).parse(rest)?;
1,692✔
276

277
            let ty = if version == QuicVersion(0) {
1,692✔
278
                QuicType::VersionNegotiation
13✔
279
            } else {
280
                // Q046 is when they started using IETF
281
                if version.is_gquic() && version != QuicVersion::Q046 {
1,679✔
282
                    match first & 0x7f {
17✔
283
                        0x7f => QuicType::Initial,
7✔
284
                        0x7e => QuicType::Retry,
1✔
285
                        0x7d => QuicType::Handshake,
×
286
                        0x7c => QuicType::ZeroRTT,
2✔
287
                        _ => {
288
                            return Err(nom8::Err::Error(QuicError::InvalidPacket));
7✔
289
                        }
290
                    }
291
                } else if version == QuicVersion::V2 {
1,662✔
292
                    match (first & 0x30) >> 4 {
127✔
293
                        0x01 => QuicType::Initial,
93✔
294
                        0x02 => QuicType::ZeroRTT,
×
295
                        0x03 => QuicType::Handshake,
33✔
296
                        0x00 => QuicType::Retry,
1✔
297
                        _ => {
298
                            return Err(nom8::Err::Error(QuicError::InvalidPacket));
×
299
                        }
300
                    }
301
                } else {
302
                    // consider as Quic version 1 (and latest drafts)
303
                    match (first & 0x30) >> 4 {
1,535✔
304
                        0x00 => QuicType::Initial,
1,236✔
305
                        0x01 => QuicType::ZeroRTT,
38✔
306
                        0x02 => QuicType::Handshake,
182✔
307
                        0x03 => QuicType::Retry,
79✔
308
                        _ => {
309
                            return Err(nom8::Err::Error(QuicError::InvalidPacket));
×
310
                        }
311
                    }
312
                }
313
            };
314

315
            let (rest, dcid, scid) = if version.is_gquic() {
1,685✔
316
                // [DCID_LEN (4)][SCID_LEN (4)]
317
                let (rest, lengths) = be_u8(rest)?;
452✔
318

319
                let mut dcid_len = (lengths & 0xF0) >> 4;
450✔
320
                let mut scid_len = lengths & 0x0F;
450✔
321

450✔
322
                // Decode dcid length if not 0
450✔
323
                if dcid_len != 0 {
450✔
324
                    dcid_len += 3;
374✔
325
                }
374✔
326

327
                // Decode scid length if not 0
328
                if scid_len != 0 {
450✔
329
                    scid_len += 3;
151✔
330
                }
299✔
331

332
                let (rest, dcid) = take(dcid_len as usize)(rest)?;
450✔
333
                let (rest, scid) = take(scid_len as usize)(rest)?;
448✔
334

335
                (rest, dcid.to_vec(), scid.to_vec())
445✔
336
            } else {
337
                let (rest, dcid_len) = be_u8(rest)?;
1,233✔
338
                let (rest, dcid) = take(dcid_len as usize)(rest)?;
1,137✔
339

340
                let (rest, scid_len) = be_u8(rest)?;
1,119✔
341
                let (rest, scid) = take(scid_len as usize)(rest)?;
1,116✔
342
                (rest, dcid.to_vec(), scid.to_vec())
1,114✔
343
            };
344

345
            let mut has_length = false;
1,559✔
346
            let rest = match ty {
1,559✔
347
                QuicType::Initial => {
348
                    if version.is_gquic() {
1,270✔
349
                        let (rest, _pkt_num) = be_u32(rest)?;
428✔
350
                        let (rest, _msg_auth_hash) = take(12usize)(rest)?;
427✔
351

352
                        rest
422✔
353
                    } else {
354
                        let (rest, token_length) = quic_var_uint(rest)?;
842✔
355
                        let (rest, _token) = take(token_length as usize)(rest)?;
834✔
356
                        has_length = true;
767✔
357
                        rest
767✔
358
                    }
359
                }
360
                QuicType::Retry => {
361
                    // opaque retry token and 16 bytes retry integrity tag
362
                    &rest[rest.len()..]
37✔
363
                }
364
                _ => rest,
252✔
365
            };
366
            let (rest, length) = if has_length {
1,478✔
367
                let (rest2, plength) = quic_var_uint(rest)?;
767✔
368
                if plength > rest2.len() as u64 {
761✔
369
                    return Err(nom8::Err::Error(QuicError::InvalidPacket));
112✔
370
                }
649✔
371
                if let Ok(length) = u16::try_from(plength) {
649✔
372
                    (rest2, length)
648✔
373
                } else {
374
                    return Err(nom8::Err::Error(QuicError::InvalidPacket));
1✔
375
                }
376
            } else if let Ok(length) = u16::try_from(rest.len()) {
711✔
377
                (rest, length)
710✔
378
            } else {
379
                return Err(nom8::Err::Error(QuicError::InvalidPacket));
1✔
380
            };
381

382
            Ok((
1,358✔
383
                rest,
1,358✔
384
                QuicHeader {
1,358✔
385
                    flags,
1,358✔
386
                    ty,
1,358✔
387
                    version,
1,358✔
388
                    version_buf: version_buf.to_vec(),
1,358✔
389
                    dcid,
1,358✔
390
                    scid,
1,358✔
391
                    length,
1,358✔
392
                },
1,358✔
393
            ))
1,358✔
394
        }
395
    }
2,402✔
396
}
397

398
impl QuicData {
399
    pub(crate) fn from_bytes(
485✔
400
        input: &[u8], past_frag: &[u8], past_fraglen: u32,
485✔
401
    ) -> Result<QuicData, QuicError> {
485✔
402
        let (_, frames) = Frame::decode_frames(input, past_frag, past_fraglen)?;
485✔
403
        Ok(QuicData { frames })
442✔
404
    }
485✔
405
}
406

407
#[cfg(test)]
408
mod tests {
409

410
    use super::*;
411
    use crate::quic::frames::{Frame, Stream, StreamTag};
412

413
    #[test]
414
    fn public_flags_test() {
415
        let pf = PublicFlags::new(0xcb);
416
        assert_eq!(
417
            PublicFlags {
418
                is_long: true,
419
                raw: 0xcb
420
            },
421
            pf
422
        );
423
    }
424

425
    const TEST_DEFAULT_CID_LENGTH: usize = 8;
426

427
    #[test]
428
    fn test_parse_gquic_unknown_version() {
429
        // Test that we can parse unknown versions
430
        let data = hex::decode("cbff00001d1091d0b10ac886039973885dfa07c469431409b15e86dd0990aaf906c5de620c4538398ffa58004482d2b19e732fc58818e57cb63569ce11abc00ea4fbac0725c5690a0838c27faf88663b48eca63baf0fba52af4eff7b4117384457c5cf1c1c0e52a1843c7676a4a35cf60c4c179e7186274c121110ace964771f31090f586b283bddbf82e9dd1d6a0e41fbaf243540dfb64f4543e1e87857c77cfc1ee9f883b97b89b6321ce30436119acfdbf2b31f4d0dbac0e5ea740ee59c8619d7c431320504c67f5c3aa9be5192f28ae378e0c8305fb95f01e7cb47c27f92cad7e8d55f699a41df3afe3894939f79e5f164771a6fe987602d975a06bfe8e6906b23601d08bcf2026eac25eca958a7b19ed7ba415e4d31b474264a479c53f01e1d35745ae62a9b148e39e2d7d33176f384d6ce4beb25d2177a8e0fbe5503ea034c9a645e5a8c98098bc5db4e11a351ac72b7079db1a858e11a6c6a4a1f44e1073903029cc08e82c48e6de00f5da7a546db371a4e49d4a213339ca074832cfeb4c39731f98a1683d7fb7db8a5b48c763440d6003fdfadd6a7fb23a62074064aafd585f6a887d5648ce71099d7d21e5cc1e14645f066016a7570d885bde4f239226884ee64fb8ec1218efec83d46ca104d9104bf46637ba3a3d8d6a88967859d60f46198e3a8495f2f211d717c6ca39987d2f4f971b502809932d973736dac67e5e28152c23d844d99fe7a5def822ca97aa433603423ee7fef57e6daa4579bb8f4f14a93663c54db415da5e8b9000d673d99c065c5922ba193eada475f2366b422d42dd86dd3b86fdef67d0e71cd200e3e24b77578f90e0e60717e3a1d6078b836d262028fc73efe7b3684b635f3001225acfd249fbe950dae7c539f015a0ce51c983c4d8e01d7e73e16946e681b2148d0ae4e72fb44d1048eb25572dae0a8016434b8c9e3fd3c93045b8afe67adc6cf7ce61a46819b712a8c24980e6c75bf007adf8910badfa102cd60c96238c8719b5e2b405905cfa6840176c7f71b7d9a2f480c36806f415b93b72821f0547b06f298584be093710a381fa352c34ba221cbcf1bbcd0b7d1aea354e460f6824df14d4bf4377a4503397e70f9993a55905ba298e798d9c69386eae8d0ebf6d871ff75e2d5a546bb8ee6ad9c92d88f950e2d8bc371aaad0d948e9f81c8151c51ee17c9257df4fd27cfeb9944b301a0fff1cb0a1b18836969457edd42f6ba370ecc2e5700bbb9fc15dc9f88c9bfc12c7dda64d423179c1eff8c53cca97056e09a07e29d02b4e553141b78d224cd79ae8056d923d41bc67eec00c943e3a62304487261d0877d54c40b7453c52e6c02141c2fa6601a357d53dddf39ae6e152501813e562a0613ca727ef3b0548c1f5a7e5036a8da84e166cec45de83bf217fb8f6c9a0ea20db0b16d1d2bb9e5e305e9d1f35e3065ab7188f79b9a841d1f6000ea744df1ba49116f7558feedf70677e35985d71b1c87c988d0b1ef2e436a54a77397546513c82bf307fc4b29152cafab11c8527eeda2addd00081c3b7b836a39920322a405c4e3774f20feda9998bf703fd10e93748b7834f3f3794d5b1f3f3099c608e84b025f5675b1526e8feee91ed04f4e91e37bd8e7089ec5a48edc2537bcddbd9d118d7937e2c25fa383186efd2f48fa3f5ebe7eaf544835bb330b61af1a95158c5e").unwrap();
431
        let (_rest, value) =
432
            QuicHeader::from_bytes(data.as_ref(), TEST_DEFAULT_CID_LENGTH).unwrap();
433
        assert_eq!(
434
            QuicHeader {
435
                flags: PublicFlags {
436
                    is_long: true,
437
                    raw: 0xcb
438
                },
439
                ty: QuicType::Initial,
440
                version: QuicVersion(0xff00001d),
441
                version_buf: vec![0xff, 0x00, 0x00, 0x1d],
442
                dcid: hex::decode("91d0b10ac886039973885dfa07c46943")
443
                    .unwrap()
444
                    .to_vec(),
445
                scid: hex::decode("09b15e86dd0990aaf906c5de620c4538398ffa58")
446
                    .unwrap()
447
                    .to_vec(),
448
                length: 1154,
449
            },
450
            value
451
        );
452
    }
453

454
    #[test]
455
    fn test_parse_gquic_q044() {
456
        let test_data = hex::decode("ff513034345005cad2cc06c4d0e400000001afac230bc5b56fb89800171b800143484c4f09000000504144008f030000534e490098030000564552009c03000043435300ac03000050444d44b00300004943534cb40300004d494453b803000043464357bc03000053464357c003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003132372e302e302e310000000001e8816092921ae87eed8086a215829158353039803a09006400000000c0000000800000").unwrap();
457
        let (rest, header) =
458
            QuicHeader::from_bytes(test_data.as_ref(), TEST_DEFAULT_CID_LENGTH).unwrap();
459

460
        assert_eq!(
461
            QuicHeader {
462
                flags: PublicFlags {
463
                    is_long: true,
464
                    raw: 0xff
465
                },
466
                ty: QuicType::Initial,
467
                version: QuicVersion::Q044,
468
                version_buf: vec![0x51, 0x30, 0x34, 0x34],
469
                dcid: hex::decode("05cad2cc06c4d0e4").unwrap().to_vec(),
470
                scid: Vec::new(),
471
                length: 1042,
472
            },
473
            header
474
        );
475

476
        let past_frag = Vec::new();
477
        let data = QuicData::from_bytes(rest, &past_frag, 0).unwrap();
478
        assert_eq!(
479
            QuicData {
480
                frames: vec![Frame::Stream(Stream {
481
                    fin: false,
482
                    stream_id: vec![0x1],
483
                    offset: vec![],
484
                    tags: Some(vec![
485
                        (StreamTag::Pad, [0x0; 911].to_vec()),
486
                        (
487
                            StreamTag::Sni,
488
                            vec![0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31]
489
                        ),
490
                        (StreamTag::Ver, vec![0x0, 0x0, 0x0, 0x0]),
491
                        (
492
                            StreamTag::Ccs,
493
                            vec![
494
                                0x1, 0xe8, 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80,
495
                                0x86, 0xa2, 0x15, 0x82, 0x91
496
                            ]
497
                        ),
498
                        (StreamTag::Pdmd, vec![0x58, 0x35, 0x30, 0x39]),
499
                        (StreamTag::Icsl, vec![0x80, 0x3a, 0x9, 0x0]),
500
                        (StreamTag::Mids, vec![0x64, 0x0, 0x0, 0x0]),
501
                        (StreamTag::Cfcw, vec![0x0, 0xc0, 0x0, 0x0]),
502
                        (StreamTag::Sfcw, vec![0x0, 0x80, 0x0, 0x0]),
503
                    ])
504
                })]
505
            },
506
            data,
507
        );
508
    }
509
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc