/src/suricata7/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::ja4::*; |
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 | 36.5k | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
88 | 36.5k | write!( |
89 | 36.5k | f, |
90 | 36.5k | "{}", |
91 | 36.5k | match self { |
92 | 2.02k | StreamTag::Aead => "AEAD", |
93 | 1.02k | StreamTag::Ccrt => "CCRT", |
94 | 827 | StreamTag::Ccs => "CCS", |
95 | 194 | StreamTag::Cetv => "CETV", |
96 | 985 | StreamTag::Cfcw => "CFCW", |
97 | 211 | StreamTag::Chlo => "CHLO", |
98 | 9.94k | StreamTag::Copt => "COPT", |
99 | 3.78k | StreamTag::Csct => "CSCT", |
100 | 194 | StreamTag::Ctim => "CTIM", |
101 | 824 | StreamTag::Icsl => "ICSL", |
102 | 825 | StreamTag::Irtt => "IRTT", |
103 | 867 | StreamTag::Kexs => "KEXS", |
104 | 824 | StreamTag::Mids => "MIDS", |
105 | 194 | StreamTag::Mspc => "MSPC", |
106 | 820 | StreamTag::Nonc => "NONC", |
107 | 824 | StreamTag::Nonp => "NONP", |
108 | 824 | StreamTag::Pad => "PAD", |
109 | 825 | StreamTag::Pdmd => "PDMD", |
110 | 809 | StreamTag::Pubs => "PUBS", |
111 | 810 | StreamTag::Scid => "SCID", |
112 | 956 | StreamTag::Scls => "SCLS", |
113 | 824 | StreamTag::Sfcw => "SFCW", |
114 | 830 | StreamTag::Smhl => "SMHL", |
115 | 1.41k | StreamTag::Sni => "SNI", |
116 | 833 | StreamTag::Sno => "SNO", |
117 | 809 | StreamTag::Stk => "STK", |
118 | 824 | StreamTag::Tcid => "TCID", |
119 | 836 | StreamTag::Uaid => "UAID", |
120 | 824 | StreamTag::Ver => "VER", |
121 | 809 | StreamTag::Xlct => "XLCT", |
122 | | } |
123 | | ) |
124 | 36.5k | } |
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 ja4: Option<JA4>, |
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 | 168k | 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 | 168k | let mut offset = 0; |
169 | 833k | while offset < input.len() { |
170 | 807k | if input[offset] != 0 { |
171 | 142k | break; |
172 | 665k | } |
173 | 665k | offset += 1; |
174 | | } |
175 | 168k | return Ok((&input[offset..], Frame::Padding)); |
176 | 168k | } |
177 | | |
178 | 45.0k | fn parse_ack_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
179 | 45.0k | let (rest, largest_acknowledged) = quic_var_uint(input)?; |
180 | 44.0k | let (rest, ack_delay) = quic_var_uint(rest)?; |
181 | 44.0k | let (rest, ack_range_count) = quic_var_uint(rest)?; |
182 | 43.5k | let (mut rest, first_ack_range) = quic_var_uint(rest)?; |
183 | | |
184 | 43.5k | for _ in 0..ack_range_count { |
185 | | //RFC9000 section 19.3.1. ACK Ranges |
186 | 37.9k | let (rest1, _gap) = quic_var_uint(rest)?; |
187 | 37.6k | let (rest1, _ack_range_length) = quic_var_uint(rest1)?; |
188 | 37.4k | rest = rest1; |
189 | | } |
190 | | |
191 | 42.9k | Ok(( |
192 | 42.9k | rest, |
193 | 42.9k | Frame::Ack(Ack { |
194 | 42.9k | largest_acknowledged, |
195 | 42.9k | ack_delay, |
196 | 42.9k | ack_range_count, |
197 | 42.9k | first_ack_range, |
198 | 42.9k | }), |
199 | 42.9k | )) |
200 | 45.0k | } |
201 | | |
202 | 1.07k | fn parse_ack3_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
203 | 1.07k | let (rest, ack) = parse_ack_frame(input)?; |
204 | 1.00k | let (rest, _ect0_count) = quic_var_uint(rest)?; |
205 | 997 | let (rest, _ect1_count) = quic_var_uint(rest)?; |
206 | 991 | let (rest, _ecn_count) = quic_var_uint(rest)?; |
207 | 975 | Ok((rest, ack)) |
208 | 1.07k | } |
209 | | |
210 | | #[derive(Clone, Debug, PartialEq, Eq)] |
211 | | pub struct QuicTlsExtension { |
212 | | pub etype: TlsExtensionType, |
213 | | pub values: Vec<Vec<u8>>, |
214 | | } |
215 | | |
216 | 35.9k | fn quic_tls_ja3_client_extends(ja3: &mut String, exts: Vec<TlsExtension>) { |
217 | 35.9k | ja3.push(','); |
218 | 35.9k | let mut dash = false; |
219 | 1.31M | for e in &exts { |
220 | 1.28M | if let TlsExtension::EllipticCurves(x) = e { |
221 | 358k | for ec in x { |
222 | 357k | if dash { |
223 | 357k | ja3.push('-'); |
224 | 357k | } else { |
225 | 503 | dash = true; |
226 | 503 | } |
227 | 357k | ja3.push_str(&ec.0.to_string()); |
228 | | } |
229 | 1.27M | } |
230 | | } |
231 | 35.9k | ja3.push(','); |
232 | 35.9k | dash = false; |
233 | 1.31M | for e in &exts { |
234 | 1.28M | if let TlsExtension::EcPointFormats(x) = e { |
235 | 110k | for ec in *x { |
236 | 108k | if dash { |
237 | 107k | ja3.push('-'); |
238 | 107k | } else { |
239 | 918 | dash = true; |
240 | 918 | } |
241 | 108k | ja3.push_str(&ec.to_string()); |
242 | | } |
243 | 1.27M | } |
244 | | } |
245 | 35.9k | } |
246 | | |
247 | | // get interesting stuff out of parsed tls extensions |
248 | 48.0k | fn quic_get_tls_extensions( |
249 | 48.0k | input: Option<&[u8]>, ja3: &mut String, mut ja4: Option<&mut JA4>, client: bool, |
250 | 48.0k | ) -> Vec<QuicTlsExtension> { |
251 | 48.0k | let mut extv = Vec::new(); |
252 | 48.0k | if let Some(extr) = input { |
253 | 40.4k | if let Ok((_, exts)) = parse_tls_extensions(extr) { |
254 | 40.4k | let mut dash = false; |
255 | 1.81M | for e in &exts { |
256 | 1.77M | let etype = TlsExtensionType::from(e); |
257 | 1.77M | if dash { |
258 | 1.75M | ja3.push('-'); |
259 | 1.75M | } else { |
260 | 22.8k | dash = true; |
261 | 22.8k | } |
262 | 1.77M | ja3.push_str(&u16::from(etype).to_string()); |
263 | 1.77M | if let Some(ref mut ja4) = ja4 { |
264 | 1.28M | ja4.add_extension(etype) |
265 | 498k | } |
266 | 1.77M | let mut values = Vec::new(); |
267 | 1.77M | match e { |
268 | 2.75k | TlsExtension::SupportedVersions(x) => { |
269 | 369k | for version in x { |
270 | 367k | let mut value = Vec::new(); |
271 | 367k | value.extend_from_slice(version.to_string().as_bytes()); |
272 | 367k | values.push(value); |
273 | 367k | if let Some(ref mut ja4) = ja4 { |
274 | 145k | ja4.set_tls_version(*version); |
275 | 221k | } |
276 | | } |
277 | | } |
278 | 1.27M | TlsExtension::SNI(x) => { |
279 | 1.41M | for sni in x { |
280 | 143k | let mut value = Vec::new(); |
281 | 143k | value.extend_from_slice(sni.1); |
282 | 143k | values.push(value); |
283 | 143k | } |
284 | | } |
285 | 892 | TlsExtension::SignatureAlgorithms(x) => { |
286 | 504k | for sigalgo in x { |
287 | 503k | let mut value = Vec::new(); |
288 | 503k | value.extend_from_slice(sigalgo.to_string().as_bytes()); |
289 | 503k | values.push(value); |
290 | 503k | if let Some(ref mut ja4) = ja4 { |
291 | 477k | ja4.add_signature_algorithm(*sigalgo) |
292 | 25.9k | } |
293 | | } |
294 | | } |
295 | 3.58k | TlsExtension::ALPN(x) => { |
296 | 3.58k | if !x.is_empty() { |
297 | 3.19k | if let Some(ref mut ja4) = ja4 { |
298 | 3.17k | ja4.set_alpn(x[0]); |
299 | 3.17k | } |
300 | 394 | } |
301 | 340k | for alpn in x { |
302 | 337k | let mut value = Vec::new(); |
303 | 337k | value.extend_from_slice(alpn); |
304 | 337k | values.push(value); |
305 | 337k | } |
306 | | } |
307 | 499k | _ => {} |
308 | | } |
309 | 1.77M | extv.push(QuicTlsExtension { etype, values }) |
310 | | } |
311 | 40.4k | if client { |
312 | 35.9k | quic_tls_ja3_client_extends(ja3, exts); |
313 | 35.9k | } |
314 | 0 | } |
315 | 7.67k | } |
316 | 48.0k | return extv; |
317 | 48.0k | } |
318 | | |
319 | 56.5k | fn parse_quic_handshake(msg: TlsMessage) -> Option<Frame> { |
320 | 56.5k | if let Handshake(hs) = msg { |
321 | 56.5k | match hs { |
322 | 42.7k | ClientHello(ch) => { |
323 | 42.7k | let mut ja3 = String::with_capacity(256); |
324 | 42.7k | ja3.push_str(&u16::from(ch.version).to_string()); |
325 | 42.7k | ja3.push(','); |
326 | 42.7k | let mut ja4 = JA4::new(); |
327 | 42.7k | ja4.set_quic(); |
328 | 42.7k | let mut dash = false; |
329 | 4.47M | for c in &ch.ciphers { |
330 | 4.43M | if dash { |
331 | 4.42M | ja3.push('-'); |
332 | 4.42M | } else { |
333 | 12.8k | dash = true; |
334 | 12.8k | } |
335 | 4.43M | ja3.push_str(&u16::from(*c).to_string()); |
336 | 4.43M | ja4.add_cipher_suite(*c); |
337 | | } |
338 | 42.7k | ja3.push(','); |
339 | 42.7k | let ciphers = ch.ciphers; |
340 | 42.7k | let extv = quic_get_tls_extensions(ch.ext, &mut ja3, Some(&mut ja4), true); |
341 | | return Some(Frame::Crypto(Crypto { |
342 | 42.7k | ciphers, |
343 | 42.7k | extv, |
344 | 42.7k | ja3: if cfg!(feature = "ja3") { |
345 | 42.7k | Some(ja3) |
346 | | } else { |
347 | 0 | None |
348 | | }, |
349 | 42.7k | ja4: if cfg!(feature = "ja4") { |
350 | 42.7k | Some(ja4) |
351 | | } else { |
352 | 0 | None |
353 | | }, |
354 | | })); |
355 | | } |
356 | 5.34k | ServerHello(sh) => { |
357 | 5.34k | let mut ja3 = String::with_capacity(256); |
358 | 5.34k | ja3.push_str(&u16::from(sh.version).to_string()); |
359 | 5.34k | ja3.push(','); |
360 | 5.34k | ja3.push_str(&u16::from(sh.cipher).to_string()); |
361 | 5.34k | ja3.push(','); |
362 | 5.34k | let ciphers = vec![sh.cipher]; |
363 | 5.34k | let extv = quic_get_tls_extensions(sh.ext, &mut ja3, None, false); |
364 | | return Some(Frame::Crypto(Crypto { |
365 | 5.34k | ciphers, |
366 | 5.34k | extv, |
367 | 5.34k | ja3: if cfg!(feature = "ja3") { |
368 | 5.34k | Some(ja3) |
369 | | } else { |
370 | 0 | None |
371 | | }, |
372 | 5.34k | ja4: None, |
373 | | })); |
374 | | } |
375 | 8.48k | _ => {} |
376 | | } |
377 | 0 | } |
378 | 8.48k | return None; |
379 | 56.5k | } |
380 | | |
381 | 152k | fn parse_crypto_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
382 | 152k | let (rest, offset) = quic_var_uint(input)?; |
383 | 152k | let (rest, length) = quic_var_uint(rest)?; |
384 | 152k | let (rest, data) = take(length as usize)(rest)?; |
385 | | |
386 | 152k | if offset > 0 { |
387 | 54.4k | return Ok(( |
388 | 54.4k | rest, |
389 | 54.4k | Frame::CryptoFrag(CryptoFrag { |
390 | 54.4k | offset, |
391 | 54.4k | length, |
392 | 54.4k | data: data.to_vec(), |
393 | 54.4k | }), |
394 | 54.4k | )); |
395 | 97.7k | } |
396 | | // if we have offset 0, try quick path : parse directly |
397 | 97.7k | match parse_tls_message_handshake(data) { |
398 | 47.3k | Ok((_, msg)) => { |
399 | 47.3k | if let Some(c) = parse_quic_handshake(msg) { |
400 | 47.2k | return Ok((rest, c)); |
401 | 124 | } |
402 | | } |
403 | | Err(nom7::Err::Incomplete(_)) => { |
404 | | // offset 0 but incomplete : save it as a fragment for later reassembly |
405 | 50.2k | return Ok(( |
406 | 50.2k | rest, |
407 | 50.2k | Frame::CryptoFrag(CryptoFrag { |
408 | 50.2k | offset, |
409 | 50.2k | length, |
410 | 50.2k | data: data.to_vec(), |
411 | 50.2k | }), |
412 | 50.2k | )); |
413 | | } |
414 | 157 | _ => {} |
415 | | } |
416 | 281 | return Err(nom7::Err::Error(QuicError::InvalidPacket)); |
417 | 152k | } |
418 | | |
419 | 134k | fn parse_tag(input: &[u8]) -> IResult<&[u8], StreamTag, QuicError> { |
420 | 134k | let (rest, tag) = be_u32(input)?; |
421 | | |
422 | 106k | let tag = StreamTag::from_u32(tag).ok_or(nom7::Err::Error(QuicError::StreamTagNoMatch(tag)))?; |
423 | | |
424 | 79.8k | Ok((rest, tag)) |
425 | 134k | } |
426 | | |
427 | 65.4k | fn parse_tag_and_offset(input: &[u8]) -> IResult<&[u8], TagOffset, QuicError> { |
428 | 65.4k | pair(parse_tag, le_u32)(input) |
429 | 65.4k | } |
430 | | |
431 | 68.8k | fn parse_crypto_stream(input: &[u8]) -> IResult<&[u8], Vec<TagValue>, QuicError> { |
432 | | // [message tag][number of tag entries: N][pad][[tag][end offset], ...N][value data] |
433 | 68.8k | let (rest, _message_tag) = parse_tag(input)?; |
434 | | |
435 | 18.9k | let (rest, num_entries) = le_u16(rest)?; |
436 | 18.3k | let (rest, _padding) = take(2usize)(rest)?; |
437 | | |
438 | 17.7k | let (rest, tags_offset) = count(complete(parse_tag_and_offset), num_entries.into())(rest)?; |
439 | | |
440 | | // Convert (Tag, Offset) to (Tag, Value) |
441 | 12.5k | let mut tags = Vec::new(); |
442 | 12.5k | let mut previous_offset = 0; |
443 | 12.5k | let mut rest = rest; |
444 | 59.6k | for (tag, offset) in tags_offset { |
445 | | // offsets should be increasing |
446 | 48.6k | let value_len = offset |
447 | 48.6k | .checked_sub(previous_offset) |
448 | 48.6k | .ok_or(nom7::Err::Error(QuicError::InvalidPacket))?; |
449 | 48.3k | let (new_rest, value) = take(value_len)(rest)?; |
450 | | |
451 | 47.1k | previous_offset = offset; |
452 | 47.1k | rest = new_rest; |
453 | | |
454 | 47.1k | tags.push((tag, value.to_vec())) |
455 | | } |
456 | | |
457 | 10.9k | Ok((rest, tags)) |
458 | 68.8k | } |
459 | | |
460 | 46.5k | fn parse_stream_frame(input: &[u8], frame_ty: u8) -> IResult<&[u8], Frame, QuicError> { |
461 | | // 0b1_f_d_ooo_ss |
462 | 46.5k | let fin = frame_ty & 0x40 == 0x40; |
463 | 46.5k | let has_data_length = frame_ty & 0x20 == 0x20; |
464 | | |
465 | 46.5k | let offset_hdr_length = { |
466 | 46.5k | let mut offset_length = (frame_ty & 0x1c) >> 2; |
467 | 46.5k | if offset_length != 0 { |
468 | 36.8k | offset_length += 1; |
469 | 36.8k | } |
470 | 46.5k | offset_length |
471 | | }; |
472 | | |
473 | 46.5k | let stream_id_hdr_length = usize::from((frame_ty & 0x03) + 1); |
474 | | |
475 | 46.5k | let (rest, stream_id) = take(stream_id_hdr_length)(input)?; |
476 | 46.1k | let (rest, offset) = take(offset_hdr_length)(rest)?; |
477 | | |
478 | 44.8k | let (rest, data_length) = if has_data_length { |
479 | 14.4k | let (rest, data_length) = be_u16(rest)?; |
480 | | |
481 | 14.2k | (rest, usize::from(data_length)) |
482 | | } else { |
483 | 30.3k | (rest, rest.len()) |
484 | | }; |
485 | | |
486 | 44.6k | let (rest, stream_data) = take(data_length)(rest)?; |
487 | | |
488 | 44.1k | let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) { |
489 | 7.03k | Some(tags) |
490 | | } else { |
491 | 37.0k | None |
492 | | }; |
493 | | |
494 | 44.1k | Ok(( |
495 | 44.1k | rest, |
496 | 44.1k | Frame::Stream(Stream { |
497 | 44.1k | fin, |
498 | 44.1k | stream_id: stream_id.to_vec(), |
499 | 44.1k | offset: offset.to_vec(), |
500 | 44.1k | tags, |
501 | 44.1k | }), |
502 | 44.1k | )) |
503 | 46.5k | } |
504 | | |
505 | 26.2k | fn parse_crypto_stream_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
506 | 26.2k | let (rest, _offset) = quic_var_uint(input)?; |
507 | 25.8k | let (rest, data_length) = quic_var_uint(rest)?; |
508 | 25.8k | if data_length > u32::MAX as u64 { |
509 | 886 | return Err(nom7::Err::Error(QuicError::Unhandled)); |
510 | 24.9k | } |
511 | 24.9k | let (rest, stream_data) = take(data_length as u32)(rest)?; |
512 | | |
513 | 24.7k | let tags = if let Ok((_, tags)) = all_consuming(parse_crypto_stream)(stream_data) { |
514 | 1.82k | Some(tags) |
515 | | } else { |
516 | 22.8k | None |
517 | | }; |
518 | | |
519 | 24.7k | Ok(( |
520 | 24.7k | rest, |
521 | 24.7k | Frame::Stream(Stream { |
522 | 24.7k | fin: false, |
523 | 24.7k | stream_id: Vec::new(), |
524 | 24.7k | offset: Vec::new(), |
525 | 24.7k | tags, |
526 | 24.7k | }), |
527 | 24.7k | )) |
528 | 26.2k | } |
529 | | |
530 | | impl Frame { |
531 | 2.03M | fn decode_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { |
532 | 2.03M | let (rest, frame_ty) = be_u8(input)?; |
533 | | |
534 | | // Special frame types |
535 | 752k | let (rest, value) = if frame_ty & 0x80 == 0x80 { |
536 | | // STREAM |
537 | 46.5k | parse_stream_frame(rest, frame_ty)? |
538 | | } else { |
539 | 705k | match frame_ty { |
540 | 168k | 0x00 => parse_padding_frame(rest)?, |
541 | 171k | 0x01 => (rest, Frame::Ping), |
542 | 44.0k | 0x02 => parse_ack_frame(rest)?, |
543 | 1.07k | 0x03 => parse_ack3_frame(rest)?, |
544 | 152k | 0x06 => parse_crypto_frame(rest)?, |
545 | 26.2k | 0x08 => parse_crypto_stream_frame(rest)?, |
546 | 141k | _ => ([].as_ref(), Frame::Unknown(rest.to_vec())), |
547 | | } |
548 | | }; |
549 | | |
550 | 745k | Ok((rest, value)) |
551 | 2.03M | } |
552 | | |
553 | 1.28M | pub(crate) fn decode_frames<'a>( |
554 | 1.28M | input: &'a [u8], past_frag: &'a [u8], past_fraglen: u32, |
555 | 1.28M | ) -> IResult<&'a [u8], Vec<Frame>, QuicError> { |
556 | 1.28M | let (rest, mut frames) = all_consuming(many0(complete(Frame::decode_frame)))(input)?; |
557 | | |
558 | | // we use the already seen past fragment data |
559 | 1.27M | let mut crypto_max_size = past_frag.len() as u64; |
560 | 1.27M | let mut crypto_total_size = 0; |
561 | | // reassemble crypto fragments : first find total size |
562 | 1.98M | for f in &frames { |
563 | 705k | if let Frame::CryptoFrag(c) = f { |
564 | 101k | if crypto_max_size < c.offset + c.length { |
565 | 22.7k | crypto_max_size = c.offset + c.length; |
566 | 78.2k | } |
567 | 101k | crypto_total_size += c.length; |
568 | 604k | } |
569 | | } |
570 | 1.27M | if crypto_max_size > 0 && crypto_max_size < QUIC_MAX_CRYPTO_FRAG_LEN { |
571 | | // we have some, and no gaps from offset 0 |
572 | 430k | let mut d = vec![0; crypto_max_size as usize]; |
573 | 430k | d[..past_frag.len()].clone_from_slice(past_frag); |
574 | 774k | for f in &frames { |
575 | 344k | if let Frame::CryptoFrag(c) = f { |
576 | 82.4k | d[c.offset as usize..(c.offset + c.length) as usize].clone_from_slice(&c.data); |
577 | 262k | } |
578 | | } |
579 | | // check that we have enough data, some new data, and data for the first byte |
580 | 430k | if crypto_total_size + past_fraglen as u64 >= crypto_max_size && crypto_total_size > 0 { |
581 | 28.0k | match parse_tls_message_handshake(&d) { |
582 | 9.24k | Ok((_, msg)) => { |
583 | 9.24k | if let Some(c) = parse_quic_handshake(msg) { |
584 | 887 | // add a parsed crypto frame |
585 | 887 | frames.push(c); |
586 | 8.35k | } |
587 | | } |
588 | 14.6k | Err(nom7::Err::Incomplete(_)) => { |
589 | 14.6k | // this means the current packet does not have all the hanshake data yet |
590 | 14.6k | let frag = CryptoFrag { |
591 | 14.6k | offset: crypto_total_size + past_fraglen as u64, |
592 | 14.6k | length: d.len() as u64, |
593 | 14.6k | data: d.to_vec(), |
594 | 14.6k | }; |
595 | 14.6k | frames.push(Frame::CryptoFrag(frag)); |
596 | 14.6k | } |
597 | 4.06k | _ => {} |
598 | | } |
599 | 402k | } else { |
600 | 402k | // pass in offset the number of bytes set in data |
601 | 402k | let frag = CryptoFrag { |
602 | 402k | offset: crypto_total_size + past_fraglen as u64, |
603 | 402k | length: d.len() as u64, |
604 | 402k | data: d.to_vec(), |
605 | 402k | }; |
606 | 402k | frames.push(Frame::CryptoFrag(frag)); |
607 | 402k | } |
608 | 849k | } else if crypto_max_size >= QUIC_MAX_CRYPTO_FRAG_LEN { |
609 | 4.69k | // just notice the engine that we have a big crypto fragment without supplying data |
610 | 4.69k | let frag = CryptoFrag { |
611 | 4.69k | offset: 0, |
612 | 4.69k | length: crypto_max_size, |
613 | 4.69k | data: Vec::new(), |
614 | 4.69k | }; |
615 | 4.69k | frames.push(Frame::CryptoFrag(frag)); |
616 | 844k | } |
617 | | |
618 | 1.27M | Ok((rest, frames)) |
619 | 1.28M | } |
620 | | } |