Skip to main content

iris_core/protocols/stream/quic/
mod.rs

1//! QUIC protocol parser.
2//!
3//! ## Remarks
4//! [QUIC-INVARIANTS] https://datatracker.ietf.org/doc/rfc8999/
5//! [QUIC-RFC9000] https://datatracker.ietf.org/doc/rfc9000/ (Quic V1)
6//! Iris currently only parses Quic Long and Short Headers and does not attempt to parse TLS or HTTP/3 out of
7//! Quic packets. The Quic protocol parser makes several assumptions about the way that quic
8//! packets will behave:
9//! - Assume that the Quic version is one as listed in the QuicVersion Enum in the quic/parser.rs file
10//! - Assume that the dcid of a short header is a maximum of 20 bytes.
11//! - Assume that the packet will not try to grease the fixed bit.
12//!   [QUIC-GREASE](https://www.rfc-editor.org/rfc/rfc9287.html)
13//!
14//! Additionally, there are a couple decisions made in the design of the quic parser:
15//! - The parser will not parse a short header dcid if it is not a part of a pre-identified connection
16//! - The payload bytes count is a lazy counter which does not try to exclude tokens for encryption,
17//!   which is a process that happens in wireshark.
18/*
19NICE-TO-HAVE: support parsing the tls out of the initial quic packet setup
20NICE-TO-HAVE support dns over quic
21NICE-TO-HAVE: support HTTP/3
22*/
23pub(crate) mod parser;
24
25use std::collections::HashSet;
26
27pub use self::header::{QuicLongHeader, QuicShortHeader};
28use crypto::Open;
29use frame::QuicFrame;
30use header::LongHeaderPacketType;
31use serde::Serialize;
32
33use super::tls::Tls;
34pub(crate) mod crypto;
35pub(crate) mod frame;
36pub(crate) mod header;
37
38/// Errors Thrown throughout QUIC parsing. These are handled by Iris and used to skip packets.
39#[derive(Debug)]
40pub enum QuicError {
41    FixedBitNotSet,
42    PacketTooShort,
43    UnknownVersion,
44    ShortHeader,
45    UnknowLongHeaderPacketType,
46    NoLongHeader,
47    UnsupportedVarLen,
48    InvalidDataIndices,
49    CryptoFail,
50    FailedHeaderProtection,
51    UnknownFrameType,
52    TlsParseFail,
53    MissingCryptoFrames,
54}
55
56/// Parsed Quic connections
57#[derive(Debug, Serialize)]
58pub struct QuicConn {
59    // All packets associated with the connection
60    pub packets: Vec<QuicPacket>,
61
62    // All cids, both src and destination, seen in Long Header packets
63    pub cids: HashSet<String>,
64
65    // Parsed TLS messsages
66    pub tls: Tls,
67
68    // Crypto needed to decrypt initial packets sent by client
69    pub client_opener: Option<Open>,
70
71    // Crypto needed to decrypt initial packets sent by server
72    pub server_opener: Option<Open>,
73
74    // Client buffer for multi-packet TLS messages
75    #[serde(skip_serializing)]
76    pub client_buffer: Vec<u8>,
77
78    // Server buffer for multi-packet TLS messages
79    #[serde(skip_serializing)]
80    pub server_buffer: Vec<u8>,
81}
82
83/// Parsed Quic Packet contents
84#[derive(Debug, Serialize)]
85pub struct QuicPacket {
86    /// Quic Short header
87    pub short_header: Option<QuicShortHeader>,
88
89    /// Quic Long header
90    pub long_header: Option<QuicLongHeader>,
91
92    /// The number of bytes contained in the estimated payload
93    pub payload_bytes_count: Option<u64>,
94
95    pub frames: Option<Vec<QuicFrame>>,
96}
97
98impl QuicPacket {
99    /// Returns the header type of the Quic packet (ie. "long" or "short")
100    pub fn header_type(&self) -> &str {
101        match &self.long_header {
102            Some(_) => "long",
103            None => match &self.short_header {
104                Some(_) => "short",
105                None => "",
106            },
107        }
108    }
109
110    /// Returns the packet type of the Quic packet
111    pub fn packet_type(&self) -> Result<LongHeaderPacketType, QuicError> {
112        match &self.long_header {
113            Some(long_header) => Ok(long_header.packet_type),
114            None => Err(QuicError::NoLongHeader),
115        }
116    }
117
118    /// Returns the version of the Quic packet
119    pub fn version(&self) -> u32 {
120        match &self.long_header {
121            Some(long_header) => long_header.version,
122            None => 0,
123        }
124    }
125
126    /// Returns the destination connection ID of the Quic packet or an empty string if it does not exist
127    pub fn dcid(&self) -> &str {
128        match &self.long_header {
129            Some(long_header) => {
130                if long_header.dcid_len > 0 {
131                    &long_header.dcid
132                } else {
133                    ""
134                }
135            }
136            None => {
137                if let Some(short_header) = &self.short_header {
138                    short_header.dcid.as_deref().unwrap_or("")
139                } else {
140                    ""
141                }
142            }
143        }
144    }
145
146    /// Returns the source connection ID of the Quic packet or an empty string if it does not exist
147    pub fn scid(&self) -> &str {
148        match &self.long_header {
149            Some(long_header) if long_header.scid_len > 0 => &long_header.scid,
150            Some(_) => "",
151            None => "",
152        }
153    }
154
155    /// Returns the number of bytes in the payload of the Quic packet
156    pub fn payload_bytes_count(&self) -> u64 {
157        self.payload_bytes_count.unwrap_or_default()
158    }
159}