]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
quic: parse gquic version Q039
authorPhilippe Antoine <contact@catenacyber.fr>
Fri, 4 Mar 2022 09:31:16 +0000 (10:31 +0100)
committerPhilippe Antoine <pantoine@oisf.net>
Tue, 2 Aug 2022 12:54:40 +0000 (14:54 +0200)
Ticket: #5166

rust/src/quic/parser.rs

index ccafbf9faecb49cf9faecd72bae1104520ca1641..4469c261bba9e0e43f37c378c71fa4ca12053304 100644 (file)
@@ -40,6 +40,7 @@ use std::convert::TryFrom;
 pub struct QuicVersion(pub u32);
 
 impl QuicVersion {
+    pub const Q039: QuicVersion = QuicVersion(0x51303339);
     pub const Q043: QuicVersion = QuicVersion(0x51303433);
     pub const Q044: QuicVersion = QuicVersion(0x51303434);
     pub const Q045: QuicVersion = QuicVersion(0x51303435);
@@ -56,6 +57,7 @@ impl QuicVersion {
 impl From<QuicVersion> for String {
     fn from(from: QuicVersion) -> Self {
         match from {
+            QuicVersion(0x51303339) => "Q039".to_string(),
             QuicVersion(0x51303433) => "Q043".to_string(),
             QuicVersion(0x51303434) => "Q044".to_string(),
             QuicVersion(0x51303435) => "Q045".to_string(),
@@ -86,16 +88,23 @@ pub enum QuicType {
     Short,
 }
 
+const QUIC_FLAG_MULTIPATH: u8 = 0x40;
+const QUIC_FLAG_DCID_LEN: u8 = 0x8;
+const QUIC_FLAG_NONCE: u8 = 0x4;
+const QUIC_FLAG_VERSION: u8 = 0x1;
+
 #[derive(Debug, PartialEq)]
 pub struct PublicFlags {
     pub is_long: bool,
+    pub raw: u8,
 }
 
 impl PublicFlags {
     pub fn new(value: u8) -> Self {
         let is_long = value & 0x80 == 0x80;
+        let raw = value;
 
-        PublicFlags { is_long }
+        PublicFlags { is_long, raw }
     }
 }
 
@@ -185,27 +194,80 @@ impl QuicHeader {
     }
 
     pub(crate) fn from_bytes(
-        input: &[u8], dcid_len: usize,
+        input: &[u8], _dcid_len: usize,
     ) -> IResult<&[u8], QuicHeader, QuicError> {
         let (rest, first) = be_u8(input)?;
         let flags = PublicFlags::new(first);
 
-        if !flags.is_long {
+        if !flags.is_long && (flags.raw & QUIC_FLAG_MULTIPATH) == 0 {
+            let (mut rest, dcid) = if (flags.raw & QUIC_FLAG_DCID_LEN) != 0 {
+                take(8_usize)(rest)?
+            } else {
+                take(0_usize)(rest)?
+            };
+            if (flags.raw & QUIC_FLAG_NONCE) != 0 && (flags.raw & QUIC_FLAG_DCID_LEN) == 0 {
+                let (rest1, _) = take(32_usize)(rest)?;
+                rest = rest1;
+            }
+            let version_buf: &[u8];
+            let version;
+            if (flags.raw & QUIC_FLAG_VERSION) != 0 {
+                let (_, version_buf1) = take(4_usize)(rest)?;
+                let (rest1, version1) = map(be_u32, QuicVersion)(rest)?;
+                rest = rest1;
+                version = version1;
+                version_buf = version_buf1;
+            } else {
+                version = QuicVersion(0);
+                version_buf = &rest[..0];
+            }
+            let pkt_num_len = 1 + ((flags.raw & 0x30) >> 4);
+            let (mut rest, _pkt_num) = take(pkt_num_len)(rest)?;
+            if (flags.raw & QUIC_FLAG_DCID_LEN) != 0 {
+                let (rest1, _msg_auth_hash) = take(12_usize)(rest)?;
+                rest = rest1;
+            }
+            let ty = if (flags.raw & QUIC_FLAG_VERSION) != 0 {
+                QuicType::Initial
+            } else {
+                QuicType::Short
+            };
+            if let Ok(plength) = u16::try_from(rest.len()) {
+                return Ok((
+                    rest,
+                    QuicHeader {
+                        flags,
+                        ty: ty,
+                        version: version,
+                        version_buf: version_buf.to_vec(),
+                        dcid: dcid.to_vec(),
+                        scid: Vec::new(),
+                        length: plength,
+                    },
+                ));
+            } else {
+                return Err(nom::Err::Error(QuicError::InvalidPacket));
+            }
+        } else if !flags.is_long {
             // Decode short header
-            let (rest, dcid) = take(dcid_len)(rest)?;
-
-            return Ok((
-                rest,
-                QuicHeader {
-                    flags,
-                    ty: QuicType::Short,
-                    version: QuicVersion(0),
-                    version_buf: Vec::new(),
-                    dcid: dcid.to_vec(),
-                    scid: Vec::new(),
-                    length: 0,
-                },
-            ));
+            // depends on version let (rest, dcid) = take(_dcid_len)(rest)?;
+
+            if let Ok(plength) = u16::try_from(rest.len()) {
+                return Ok((
+                    rest,
+                    QuicHeader {
+                        flags,
+                        ty: QuicType::Short,
+                        version: QuicVersion(0),
+                        version_buf: Vec::new(),
+                        dcid: Vec::new(),
+                        scid: Vec::new(),
+                        length: plength,
+                    },
+                ));
+            } else {
+                return Err(nom::Err::Error(QuicError::InvalidPacket));
+            }
         } else {
             // Decode Long header
             let (_, version_buf) = take(4_usize)(rest)?;
@@ -335,7 +397,13 @@ mod tests {
     #[test]
     fn public_flags_test() {
         let pf = PublicFlags::new(0xcb);
-        assert_eq!(PublicFlags { is_long: true }, pf);
+        assert_eq!(
+            PublicFlags {
+                is_long: true,
+                raw: 0xcb
+            },
+            pf
+        );
     }
 
     const TEST_DEFAULT_CID_LENGTH: usize = 8;
@@ -348,7 +416,10 @@ mod tests {
             QuicHeader::from_bytes(data.as_ref(), TEST_DEFAULT_CID_LENGTH).unwrap();
         assert_eq!(
             QuicHeader {
-                flags: PublicFlags { is_long: true },
+                flags: PublicFlags {
+                    is_long: true,
+                    raw: 0xcb
+                },
                 ty: QuicType::Initial,
                 version: QuicVersion(0xff00001d),
                 version_buf: vec![0xff, 0x00, 0x00, 0x1d],
@@ -372,7 +443,10 @@ mod tests {
 
         assert_eq!(
             QuicHeader {
-                flags: PublicFlags { is_long: true },
+                flags: PublicFlags {
+                    is_long: true,
+                    raw: 0xff
+                },
                 ty: QuicType::Initial,
                 version: QuicVersion::Q044,
                 version_buf: vec![0x51, 0x30, 0x34, 0x34],