/src/suricata8/rust/src/quic/frames.rs
Line | Count | Source |
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 | | |
18 | | use super::error::QuicError; |
19 | | use super::quic::QUIC_MAX_CRYPTO_FRAG_LEN; |
20 | | use crate::handshake::HandshakeParams; |
21 | | use crate::quic::parser::quic_var_uint; |
22 | | use nom7::bytes::complete::take; |
23 | | use nom7::combinator::{all_consuming, complete}; |
24 | | use nom7::multi::{count, many0}; |
25 | | use nom7::number::complete::{be_u16, be_u32, be_u8, le_u16, le_u32}; |
26 | | use nom7::sequence::pair; |
27 | | use nom7::IResult; |
28 | | use num::FromPrimitive; |
29 | | use std::fmt; |
30 | | use tls_parser::TlsMessage::Handshake; |
31 | | use tls_parser::TlsMessageHandshake::{ClientHello, ServerHello}; |
32 | | use tls_parser::{ |
33 | | parse_tls_extensions, parse_tls_message_handshake, TlsCipherSuiteID, TlsExtension, |
34 | | TlsExtensionType, TlsMessage, |
35 | | }; |
36 | | |
37 | | /// Tuple of StreamTag and offset |
38 | | type TagOffset = (StreamTag, u32); |
39 | | |
40 | | /// Tuple of StreamTag and value |
41 | | type TagValue = (StreamTag, Vec<u8>); |
42 | | |
43 | | #[derive(Debug, PartialEq)] |
44 | | pub(crate) struct Stream { |
45 | | pub fin: bool, |
46 | | pub stream_id: Vec<u8>, |
47 | | pub offset: Vec<u8>, |
48 | | pub tags: Option<Vec<TagValue>>, |
49 | | } |
50 | | |
51 | | #[repr(u32)] |
52 | | #[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)] |
53 | | pub(crate) enum StreamTag { |
54 | | Aead = 0x41454144, |
55 | | Ccrt = 0x43435254, |
56 | | Ccs = 0x43435300, |
57 | | Cetv = 0x43455456, |
58 | | Cfcw = 0x43464357, |
59 | | Chlo = 0x43484c4f, |
60 | | Copt = 0x434f5054, |
61 | | Csct = 0x43534354, |
62 | | Ctim = 0x4354494d, |
63 | | Icsl = 0x4943534c, |
64 | | Irtt = 0x49525454, |
65 | | Kexs = 0x4b455853, |
66 | | Mids = 0x4d494453, |
67 | | Mspc = 0x4d535043, |
68 | | Nonc = 0x4e4f4e43, |
69 | | Nonp = 0x4e4f4e50, |
70 | | Pad = 0x50414400, |
71 | | Pdmd = 0x50444d44, |
72 | | Pubs = 0x50554253, |
73 | | Scid = 0x53434944, |
74 | | Scls = 0x53434c53, |
75 | | Sfcw = 0x53464357, |
76 | | Smhl = 0x534d484c, |
77 | | Sni = 0x534e4900, |
78 | | Sno = 0x534e4f00, |
79 | | Stk = 0x53544b00, |
80 | | Tcid = 0x54434944, |
81 | | Uaid = 0x55414944, |
82 | | Ver = 0x56455200, |
83 | | Xlct = 0x584c4354, |
84 | | } |
85 | | |
86 | | impl fmt::Display for StreamTag { |
87 | 17 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
88 | 17 | write!( |
89 | 17 | f, |
90 | 17 | "{}", |
91 | 17 | match self { |
92 | 0 | StreamTag::Aead => "AEAD", |
93 | 0 | StreamTag::Ccrt => "CCRT", |
94 | 1 | StreamTag::Ccs => "CCS", |
95 | 0 | StreamTag::Cetv => "CETV", |
96 | 1 | StreamTag::Cfcw => "CFCW", |
97 | 0 | StreamTag::Chlo => "CHLO", |
98 | 1 | StreamTag::Copt => "COPT", |
99 | 1 | StreamTag::Csct => "CSCT", |
100 | 0 | StreamTag::Ctim => "CTIM", |
101 | 1 | StreamTag::Icsl => "ICSL", |
102 | 1 | StreamTag::Irtt => "IRTT", |
103 | 0 | StreamTag::Kexs => "KEXS", |
104 | 1 | StreamTag::Mids => "MIDS", |
105 | 0 | StreamTag::Mspc => "MSPC", |
106 | 0 | StreamTag::Nonc => "NONC", |
107 | 1 | StreamTag::Nonp => "NONP", |
108 | 1 | StreamTag::Pad => "PAD", |
109 | 1 | StreamTag::Pdmd => "PDMD", |
110 | 0 | StreamTag::Pubs => "PUBS", |
111 | 0 | StreamTag::Scid => "SCID", |
112 | 1 | StreamTag::Scls => "SCLS", |
113 | 1 | StreamTag::Sfcw => "SFCW", |
114 | 1 | StreamTag::Smhl => "SMHL", |
115 | 1 | StreamTag::Sni => "SNI", |
116 | 0 | StreamTag::Sno => "SNO", |
117 | 0 | StreamTag::Stk => "STK", |
118 | 1 | StreamTag::Tcid => "TCID", |
119 | 1 | StreamTag::Uaid => "UAID", |
120 | 1 | StreamTag::Ver => "VER", |
121 | 0 | StreamTag::Xlct => "XLCT", |
122 | | } |
123 | | ) |
124 | 17 | } |
125 | | } |
126 | | |
127 | | #[derive(Debug, PartialEq)] |
128 | | pub(crate) struct Ack { |
129 | | pub largest_acknowledged: u64, |
130 | | pub ack_delay: u64, |
131 | | pub ack_range_count: u64, |
132 | | pub first_ack_range: u64, |
133 | | } |
134 | | |
135 | | #[derive(Debug, PartialEq)] |
136 | | pub(crate) struct Crypto { |
137 | | pub ciphers: Vec<TlsCipherSuiteID>, |
138 | | // We remap the Vec<TlsExtension> from tls_parser::parse_tls_extensions because of |
139 | | // the lifetime of TlsExtension due to references to the slice used for parsing |
140 | | pub extv: Vec<QuicTlsExtension>, |
141 | | pub ja3: Option<String>, |
142 | | pub hs: Option<HandshakeParams>, |
143 | | } |
144 | | |
145 | | #[derive(Debug, PartialEq)] |
146 | | pub(crate) struct CryptoFrag { |
147 | | pub offset: u64, |
148 | | pub length: u64, |
149 | | pub data: Vec<u8>, |
150 | | } |
151 | | |
152 | | #[derive(Debug, PartialEq)] |
153 | | pub(crate) enum Frame { |
154 | | Padding, |
155 | | Ping, |
156 | | Ack(Ack), |
157 | | // this is more than a crypto frame : it contains a fully parsed tls hello |
158 | | Crypto(Crypto), |
159 | | // this is a regular quic crypto frame : they can be reassembled |
160 | | // in order to parse a tls hello |
161 | | CryptoFrag(CryptoFrag), |
162 | | Stream(Stream), |
163 | | Unknown(Vec<u8>), |
164 | | } |
165 | | |
166 | 21.6k | fn parse_padding_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
167 | | // nom take_while: cannot infer type for type parameter `Error` declared on the function `take_while` |
168 | 21.6k | let mut offset = 0; |
169 | 114k | while offset < input.len() { |
170 | 113k | if input[offset] != 0 { |
171 | 20.2k | break; |
172 | 93.1k | } |
173 | 93.1k | offset += 1; |
174 | | } |
175 | 21.6k | return Ok((&input[offset..], Frame::Padding)); |
176 | 21.6k | } |
177 | | |
178 | 2.88k | fn parse_ack_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
179 | 2.88k | let (rest, largest_acknowledged) = quic_var_uint(input)?; |
180 | 2.87k | let (rest, ack_delay) = quic_var_uint(rest)?; |
181 | 2.86k | let (rest, ack_range_count) = quic_var_uint(rest)?; |
182 | 2.86k | let (mut rest, first_ack_range) = quic_var_uint(rest)?; |
183 | | |
184 | 2.86k | for _ in 0..ack_range_count { |
185 | | //RFC9000 section 19.3.1. ACK Ranges |
186 | 6.19k | let (rest1, _gap) = quic_var_uint(rest)?; |
187 | 6.14k | let (rest1, _ack_range_length) = quic_var_uint(rest1)?; |
188 | 6.07k | rest = rest1; |
189 | | } |
190 | | |
191 | 2.74k | Ok(( |
192 | 2.74k | rest, |
193 | 2.74k | Frame::Ack(Ack { |
194 | 2.74k | largest_acknowledged, |
195 | 2.74k | ack_delay, |
196 | 2.74k | ack_range_count, |
197 | 2.74k | first_ack_range, |
198 | 2.74k | }), |
199 | 2.74k | )) |
200 | 2.88k | } |
201 | | |
202 | 591 | fn parse_ack3_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
203 | 591 | let (rest, ack) = parse_ack_frame(input)?; |
204 | 561 | let (rest, _ect0_count) = quic_var_uint(rest)?; |
205 | 559 | let (rest, _ect1_count) = quic_var_uint(rest)?; |
206 | 557 | let (rest, _ecn_count) = quic_var_uint(rest)?; |
207 | 555 | Ok((rest, ack)) |
208 | 591 | } |
209 | | |
210 | | #[derive(Clone, Debug, PartialEq, Eq)] |
211 | | pub struct QuicTlsExtension { |
212 | | pub etype: TlsExtensionType, |
213 | | pub values: Vec<Vec<u8>>, |
214 | | } |
215 | | |
216 | 0 | fn quic_tls_ja3_client_extends(ja3: &mut String, exts: Vec<TlsExtension>) { |
217 | 0 | ja3.push(','); |
218 | 0 | let mut dash = false; |
219 | 0 | for e in &exts { |
220 | 0 | if let TlsExtension::EllipticCurves(x) = e { |
221 | 0 | for ec in x { |
222 | 0 | if dash { |
223 | 0 | ja3.push('-'); |
224 | 0 | } else { |
225 | 0 | dash = true; |
226 | 0 | } |
227 | 0 | ja3.push_str(&ec.0.to_string()); |
228 | | } |
229 | 0 | } |
230 | | } |
231 | 0 | ja3.push(','); |
232 | 0 | dash = false; |
233 | 0 | for e in &exts { |
234 | 0 | if let TlsExtension::EcPointFormats(x) = e { |
235 | 0 | for ec in *x { |
236 | 0 | if dash { |
237 | 0 | ja3.push('-'); |
238 | 0 | } else { |
239 | 0 | dash = true; |
240 | 0 | } |
241 | 0 | ja3.push_str(&ec.to_string()); |
242 | | } |
243 | 0 | } |
244 | | } |
245 | 0 | } |
246 | | |
247 | | // get interesting stuff out of parsed tls extensions |
248 | 0 | fn quic_get_tls_extensions( |
249 | 0 | input: Option<&[u8]>, ja3: &mut String, mut hs: Option<&mut HandshakeParams>, client: bool, |
250 | 0 | ) -> Vec<QuicTlsExtension> { |
251 | 0 | let mut extv = Vec::new(); |
252 | 0 | if let Some(extr) = input { |
253 | 0 | if let Ok((_, exts)) = parse_tls_extensions(extr) { |
254 | 0 | let mut dash = false; |
255 | 0 | for e in &exts { |
256 | 0 | let etype = TlsExtensionType::from(e); |
257 | 0 | if dash { |
258 | 0 | ja3.push('-'); |
259 | 0 | } else { |
260 | 0 | dash = true; |
261 | 0 | } |
262 | 0 | ja3.push_str(&u16::from(etype).to_string()); |
263 | 0 | if let Some(ref mut hs) = hs { |
264 | 0 | hs.add_extension(etype) |
265 | 0 | } |
266 | 0 | let mut values = Vec::new(); |
267 | 0 | match e { |
268 | 0 | TlsExtension::SupportedVersions(x) => { |
269 | 0 | for version in x { |
270 | 0 | let mut value = Vec::new(); |
271 | 0 | value.extend_from_slice(version.to_string().as_bytes()); |
272 | 0 | values.push(value); |
273 | 0 | if let Some(ref mut hs) = hs { |
274 | 0 | hs.set_tls_version(*version); |
275 | 0 | } |
276 | | } |
277 | | } |
278 | 0 | TlsExtension::SNI(x) => { |
279 | 0 | for sni in x { |
280 | 0 | let mut value = Vec::new(); |
281 | 0 | value.extend_from_slice(sni.1); |
282 | 0 | values.push(value); |
283 | 0 | } |
284 | | } |
285 | 0 | TlsExtension::SignatureAlgorithms(x) => { |
286 | 0 | for sigalgo in x { |
287 | 0 | let mut value = Vec::new(); |
288 | 0 | value.extend_from_slice(sigalgo.to_string().as_bytes()); |
289 | 0 | values.push(value); |
290 | 0 | if let Some(ref mut hs) = hs { |
291 | 0 | hs.add_signature_algorithm(*sigalgo) |
292 | 0 | } |
293 | | } |
294 | | } |
295 | 0 | TlsExtension::ALPN(x) => { |
296 | 0 | if !x.is_empty() { |
297 | 0 | if let Some(ref mut hs) = hs { |
298 | 0 | hs.add_alpn(x[0]); |
299 | 0 | } |
300 | 0 | } |
301 | 0 | for alpn in x { |
302 | 0 | let mut value = Vec::new(); |
303 | 0 | value.extend_from_slice(alpn); |
304 | 0 | values.push(value); |
305 | 0 | } |
306 | | } |
307 | 0 | _ => {} |
308 | | } |
309 | 0 | extv.push(QuicTlsExtension { etype, values }) |
310 | | } |
311 | 0 | if client { |
312 | 0 | quic_tls_ja3_client_extends(ja3, exts); |
313 | 0 | } |
314 | 0 | } |
315 | 0 | } |
316 | 0 | return extv; |
317 | 0 | } |
318 | | |
319 | 90 | fn parse_quic_handshake(msg: TlsMessage) -> Option<Frame> { |
320 | 90 | if let Handshake(hs) = msg { |
321 | 90 | match hs { |
322 | 0 | ClientHello(ch) => { |
323 | 0 | let mut ja3 = String::with_capacity(256); |
324 | 0 | ja3.push_str(&u16::from(ch.version).to_string()); |
325 | 0 | ja3.push(','); |
326 | 0 | let mut hs = HandshakeParams { quic: true, ..Default::default() }; |
327 | 0 | let mut dash = false; |
328 | 0 | for c in &ch.ciphers { |
329 | 0 | if dash { |
330 | 0 | ja3.push('-'); |
331 | 0 | } else { |
332 | 0 | dash = true; |
333 | 0 | } |
334 | 0 | ja3.push_str(&u16::from(*c).to_string()); |
335 | 0 | hs.add_cipher_suite(*c); |
336 | | } |
337 | 0 | ja3.push(','); |
338 | 0 | let ciphers = ch.ciphers; |
339 | 0 | let extv = quic_get_tls_extensions(ch.ext, &mut ja3, Some(&mut hs), true); |
340 | | return Some(Frame::Crypto(Crypto { |
341 | 0 | ciphers, |
342 | 0 | extv, |
343 | 0 | ja3: if cfg!(feature = "ja3") { |
344 | 0 | Some(ja3) |
345 | | } else { |
346 | 0 | None |
347 | | }, |
348 | 0 | hs: if cfg!(feature = "ja4") { |
349 | 0 | Some(hs) |
350 | | } else { |
351 | 0 | None |
352 | | }, |
353 | | })); |
354 | | } |
355 | 0 | ServerHello(sh) => { |
356 | 0 | let mut ja3 = String::with_capacity(256); |
357 | 0 | ja3.push_str(&u16::from(sh.version).to_string()); |
358 | 0 | ja3.push(','); |
359 | 0 | ja3.push_str(&u16::from(sh.cipher).to_string()); |
360 | 0 | ja3.push(','); |
361 | 0 | let ciphers = vec![sh.cipher]; |
362 | 0 | let extv = quic_get_tls_extensions(sh.ext, &mut ja3, None, false); |
363 | | return Some(Frame::Crypto(Crypto { |
364 | 0 | ciphers, |
365 | 0 | extv, |
366 | 0 | ja3: if cfg!(feature = "ja3") { |
367 | 0 | Some(ja3) |
368 | | } else { |
369 | 0 | None |
370 | | }, |
371 | 0 | hs: None, |
372 | | })); |
373 | | } |
374 | 90 | _ => {} |
375 | | } |
376 | 0 | } |
377 | 90 | return None; |
378 | 90 | } |
379 | | |
380 | 8.57k | fn parse_crypto_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
381 | 8.57k | let (rest, offset) = quic_var_uint(input)?; |
382 | 8.57k | let (rest, length) = quic_var_uint(rest)?; |
383 | 8.57k | let (rest, data) = take(length as usize)(rest)?; |
384 | | |
385 | 8.49k | if offset > 0 { |
386 | 3.43k | return Ok(( |
387 | 3.43k | rest, |
388 | 3.43k | Frame::CryptoFrag(CryptoFrag { |
389 | 3.43k | offset, |
390 | 3.43k | length, |
391 | 3.43k | data: data.to_vec(), |
392 | 3.43k | }), |
393 | 3.43k | )); |
394 | 5.06k | } |
395 | | // if we have offset 0, try quick path : parse directly |
396 | 5.06k | match parse_tls_message_handshake(data) { |
397 | 15 | Ok((_, msg)) => { |
398 | 15 | if let Some(c) = parse_quic_handshake(msg) { |
399 | 0 | return Ok((rest, c)); |
400 | 15 | } |
401 | | } |
402 | | Err(nom7::Err::Incomplete(_)) => { |
403 | | // offset 0 but incomplete : save it as a fragment for later reassembly |
404 | 5.03k | return Ok(( |
405 | 5.03k | rest, |
406 | 5.03k | Frame::CryptoFrag(CryptoFrag { |
407 | 5.03k | offset, |
408 | 5.03k | length, |
409 | 5.03k | data: data.to_vec(), |
410 | 5.03k | }), |
411 | 5.03k | )); |
412 | | } |
413 | 15 | _ => {} |
414 | | } |
415 | 30 | return Err(nom7::Err::Error(QuicError::InvalidPacket)); |
416 | 8.57k | } |
417 | | |
418 | 4.97k | fn parse_tag(input: &[u8]) -> IResult<&[u8], StreamTag, QuicError> { |
419 | 4.97k | let (rest, tag) = be_u32(input)?; |
420 | | |
421 | 2.03k | let tag = StreamTag::from_u32(tag).ok_or(nom7::Err::Error(QuicError::StreamTagNoMatch(tag)))?; |
422 | | |
423 | 35 | Ok((rest, tag)) |
424 | 4.97k | } |
425 | | |
426 | 28 | fn parse_tag_and_offset(input: &[u8]) -> IResult<&[u8], TagOffset, QuicError> { |
427 | 28 | pair(parse_tag, le_u32)(input) |
428 | 28 | } |
429 | | |
430 | 4.94k | fn parse_crypto_stream(input: &[u8]) -> IResult<&[u8], Vec<TagValue>, QuicError> { |
431 | | // [message tag][number of tag entries: N][pad][[tag][end offset], ...N][value data] |
432 | 4.94k | let (rest, _message_tag) = parse_tag(input)?; |
433 | | |
434 | 14 | let (rest, num_entries) = le_u16(rest)?; |
435 | 13 | let (rest, _padding) = take(2usize)(rest)?; |
436 | | |
437 | 12 | let (rest, tags_offset) = count(complete(parse_tag_and_offset), num_entries.into())(rest)?; |
438 | | |
439 | | // Convert (Tag, Offset) to (Tag, Value) |
440 | 5 | let mut tags = Vec::new(); |
441 | 5 | let mut previous_offset = 0; |
442 | 5 | let mut rest = rest; |
443 | 23 | for (tag, offset) in tags_offset { |
444 | | // offsets should be increasing |
445 | 20 | let value_len = offset |
446 | 20 | .checked_sub(previous_offset) |
447 | 20 | .ok_or(nom7::Err::Error(QuicError::InvalidPacket))?; |
448 | 20 | let (new_rest, value) = take(value_len)(rest)?; |
449 | | |
450 | 18 | previous_offset = offset; |
451 | 18 | rest = new_rest; |
452 | | |
453 | 18 | tags.push((tag, value.to_vec())) |
454 | | } |
455 | | |
456 | 3 | Ok((rest, tags)) |
457 | 4.94k | } |
458 | | |
459 | 3.55k | fn parse_stream_frame(input: &[u8], frame_ty: u8) -> IResult<&[u8], Frame, QuicError> { |
460 | | // 0b1_f_d_ooo_ss |
461 | 3.55k | let fin = frame_ty & 0x40 == 0x40; |
462 | 3.55k | let has_data_length = frame_ty & 0x20 == 0x20; |
463 | | |
464 | 3.55k | let offset_hdr_length = { |
465 | 3.55k | let mut offset_length = (frame_ty & 0x1c) >> 2; |
466 | 3.55k | if offset_length != 0 { |
467 | 3.13k | offset_length += 1; |
468 | 3.13k | } |
469 | 3.55k | offset_length |
470 | | }; |
471 | | |
472 | 3.55k | let stream_id_hdr_length = usize::from((frame_ty & 0x03) + 1); |
473 | | |
474 | 3.55k | let (rest, stream_id) = take(stream_id_hdr_length)(input)?; |
475 | 3.44k | let (rest, offset) = take(offset_hdr_length)(rest)?; |
476 | | |
477 | 3.41k | let (rest, data_length) = if has_data_length { |
478 | 1.95k | let (rest, data_length) = be_u16(rest)?; |
479 | | |
480 | 1.95k | (rest, usize::from(data_length)) |
481 | | } else { |
482 | 1.46k | (rest, rest.len()) |
483 | | }; |
484 | | |
485 | 3.41k | let (rest, stream_data) = take(data_length)(rest)?; |
486 | | |
487 | 3.34k | let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) { |
488 | 1 | Some(tags) |
489 | | } else { |
490 | 3.34k | None |
491 | | }; |
492 | | |
493 | 3.34k | Ok(( |
494 | 3.34k | rest, |
495 | 3.34k | Frame::Stream(Stream { |
496 | 3.34k | fin, |
497 | 3.34k | stream_id: stream_id.to_vec(), |
498 | 3.34k | offset: offset.to_vec(), |
499 | 3.34k | tags, |
500 | 3.34k | }), |
501 | 3.34k | )) |
502 | 3.55k | } |
503 | | |
504 | 1.67k | fn parse_crypto_stream_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
505 | 1.67k | let (rest, _offset) = quic_var_uint(input)?; |
506 | 1.67k | let (rest, data_length) = quic_var_uint(rest)?; |
507 | 1.66k | if data_length > u32::MAX as u64 { |
508 | 47 | return Err(nom7::Err::Error(QuicError::Unhandled)); |
509 | 1.61k | } |
510 | 1.61k | let (rest, stream_data) = take(data_length as u32)(rest)?; |
511 | | |
512 | 1.59k | let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) { |
513 | 0 | Some(tags) |
514 | | } else { |
515 | 1.59k | None |
516 | | }; |
517 | | |
518 | 1.59k | Ok(( |
519 | 1.59k | rest, |
520 | 1.59k | Frame::Stream(Stream { |
521 | 1.59k | fin: false, |
522 | 1.59k | stream_id: Vec::new(), |
523 | 1.59k | offset: Vec::new(), |
524 | 1.59k | tags, |
525 | 1.59k | }), |
526 | 1.59k | )) |
527 | 1.67k | } |
528 | | |
529 | | impl Frame { |
530 | 185k | fn decode_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
531 | 185k | let (rest, frame_ty) = be_u8(input)?; |
532 | | |
533 | | // Special frame types |
534 | 54.7k | let (rest, value) = if frame_ty & 0x80 == 0x80 { |
535 | | // STREAM |
536 | 3.55k | parse_stream_frame(rest, frame_ty)? |
537 | | } else { |
538 | 51.1k | match frame_ty { |
539 | 21.6k | 0x00 => parse_padding_frame(rest)?, |
540 | 2.51k | 0x01 => (rest, Frame::Ping), |
541 | 2.29k | 0x02 => parse_ack_frame(rest)?, |
542 | 591 | 0x03 => parse_ack3_frame(rest)?, |
543 | 8.57k | 0x06 => parse_crypto_frame(rest)?, |
544 | 1.67k | 0x08 => parse_crypto_stream_frame(rest)?, |
545 | 13.9k | _ => ([].as_ref(), Frame::Unknown(rest.to_vec())), |
546 | | } |
547 | | }; |
548 | | |
549 | 54.1k | Ok((rest, value)) |
550 | 185k | } |
551 | | |
552 | 131k | pub(crate) fn decode_frames<'a>( |
553 | 131k | input: &'a [u8], past_frag: &'a [u8], past_fraglen: u32, |
554 | 131k | ) -> IResult<&'a [u8], Vec<Frame>, QuicError> { |
555 | 131k | let (rest, mut frames) = all_consuming(many0(complete(Frame::decode_frame)))(input)?; |
556 | | |
557 | | // we use the already seen past fragment data |
558 | 130k | let mut crypto_max_size = past_frag.len() as u64; |
559 | 130k | let mut crypto_total_size = 0; |
560 | | // reassemble crypto fragments : first find total size |
561 | 183k | for f in &frames { |
562 | 52.7k | if let Frame::CryptoFrag(c) = f { |
563 | 8.33k | if crypto_max_size < c.offset + c.length { |
564 | 2.46k | crypto_max_size = c.offset + c.length; |
565 | 5.87k | } |
566 | 8.33k | crypto_total_size += c.length; |
567 | 44.4k | } |
568 | | } |
569 | 130k | if crypto_max_size > 0 && crypto_max_size < QUIC_MAX_CRYPTO_FRAG_LEN { |
570 | | // we have some, and no gaps from offset 0 |
571 | 117k | let mut d = vec![0; crypto_max_size as usize]; |
572 | 117k | d[..past_frag.len()].clone_from_slice(past_frag); |
573 | 145k | for f in &frames { |
574 | 27.9k | if let Frame::CryptoFrag(c) = f { |
575 | 5.80k | d[c.offset as usize..(c.offset + c.length) as usize].clone_from_slice(&c.data); |
576 | 22.1k | } |
577 | | } |
578 | | // check that we have enough data, some new data, and data for the first byte |
579 | 117k | if crypto_total_size + past_fraglen as u64 >= crypto_max_size && crypto_total_size > 0 { |
580 | 3.99k | match parse_tls_message_handshake(&d) { |
581 | 75 | Ok((_, msg)) => { |
582 | 75 | if let Some(c) = parse_quic_handshake(msg) { |
583 | 0 | // add a parsed crypto frame |
584 | 0 | frames.push(c); |
585 | 75 | } |
586 | | } |
587 | 3.83k | Err(nom7::Err::Incomplete(_)) => { |
588 | 3.83k | // this means the current packet does not have all the hanshake data yet |
589 | 3.83k | let frag = CryptoFrag { |
590 | 3.83k | offset: crypto_total_size + past_fraglen as u64, |
591 | 3.83k | length: d.len() as u64, |
592 | 3.83k | data: d.to_vec(), |
593 | 3.83k | }; |
594 | 3.83k | frames.push(Frame::CryptoFrag(frag)); |
595 | 3.83k | } |
596 | 79 | _ => {} |
597 | | } |
598 | 113k | } else { |
599 | 113k | // pass in offset the number of bytes set in data |
600 | 113k | let frag = CryptoFrag { |
601 | 113k | offset: crypto_total_size + past_fraglen as u64, |
602 | 113k | length: d.len() as u64, |
603 | 113k | data: d.to_vec(), |
604 | 113k | }; |
605 | 113k | frames.push(Frame::CryptoFrag(frag)); |
606 | 113k | } |
607 | 12.7k | } else if crypto_max_size >= QUIC_MAX_CRYPTO_FRAG_LEN { |
608 | 1.98k | // just notice the engine that we have a big crypto fragment without supplying data |
609 | 1.98k | let frag = CryptoFrag { |
610 | 1.98k | offset: 0, |
611 | 1.98k | length: crypto_max_size, |
612 | 1.98k | data: Vec::new(), |
613 | 1.98k | }; |
614 | 1.98k | frames.push(Frame::CryptoFrag(frag)); |
615 | 10.7k | } |
616 | | |
617 | 130k | Ok((rest, frames)) |
618 | 131k | } |
619 | | } |