Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/quic/quic.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::{
19
    crypto::{quic_keys_initial, QuicKeys, AES128_KEY_LEN},
20
    cyu::Cyu,
21
    frames::{Frame, QuicTlsExtension, StreamTag},
22
    parser::{quic_pkt_num, QuicData, QuicHeader, QuicType},
23
};
24
use crate::applayer::{self, *};
25
use crate::core::{AppProto, Direction, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_UDP};
26
use std::collections::VecDeque;
27
use std::ffi::CString;
28
use tls_parser::TlsExtensionType;
29
30
static mut ALPROTO_QUIC: AppProto = ALPROTO_UNKNOWN;
31
32
const DEFAULT_DCID_LEN: usize = 16;
33
const PKT_NUM_BUF_MAX_LEN: usize = 4;
34
pub(super) const QUIC_MAX_CRYPTO_FRAG_LEN: u64 = 65535;
35
36
#[derive(FromPrimitive, Debug, AppLayerEvent)]
37
pub enum QuicEvent {
38
    FailedDecrypt,
39
    ErrorOnData,
40
    ErrorOnHeader,
41
    CryptoFragTooLong,
42
}
43
44
#[derive(Debug)]
45
pub struct QuicTransaction {
46
    tx_id: u64,
47
    pub header: QuicHeader,
48
    pub cyu: Vec<Cyu>,
49
    pub sni: Option<Vec<u8>>,
50
    pub ua: Option<Vec<u8>>,
51
    pub extv: Vec<QuicTlsExtension>,
52
    pub ja3: Option<String>,
53
    pub ja4: Option<String>,
54
    pub client: bool,
55
    tx_data: AppLayerTxData,
56
}
57
58
impl QuicTransaction {
59
1.75M
    fn new(
60
1.75M
        header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
61
1.75M
        extv: Vec<QuicTlsExtension>, ja3: Option<String>, ja4: Option<String>, client: bool,
62
1.75M
    ) -> Self {
63
1.75M
        let direction = if client {
64
1.06M
            Direction::ToServer
65
        } else {
66
690k
            Direction::ToClient
67
        };
68
1.75M
        let cyu = Cyu::generate(&header, &data.frames);
69
1.75M
        QuicTransaction {
70
1.75M
            tx_id: 0,
71
1.75M
            header,
72
1.75M
            cyu,
73
1.75M
            sni,
74
1.75M
            ua,
75
1.75M
            extv,
76
1.75M
            ja3,
77
1.75M
            ja4,
78
1.75M
            client,
79
1.75M
            tx_data: AppLayerTxData::for_direction(direction),
80
1.75M
        }
81
1.75M
    }
82
83
10.8k
    fn new_empty(client: bool, header: QuicHeader) -> Self {
84
10.8k
        let direction = if client {
85
10.4k
            Direction::ToServer
86
        } else {
87
342
            Direction::ToClient
88
        };
89
10.8k
        QuicTransaction {
90
10.8k
            tx_id: 0,
91
10.8k
            header,
92
10.8k
            cyu: Vec::new(),
93
10.8k
            sni: None,
94
10.8k
            ua: None,
95
10.8k
            extv: Vec::new(),
96
10.8k
            ja3: None,
97
10.8k
            ja4: None,
98
10.8k
            client,
99
10.8k
            tx_data: AppLayerTxData::for_direction(direction),
100
10.8k
        }
101
10.8k
    }
102
}
103
104
pub struct QuicState {
105
    state_data: AppLayerStateData,
106
    max_tx_id: u64,
107
    keys: Option<QuicKeys>,
108
    /// crypto fragment data already seen and reassembled to client
109
    crypto_frag_tc: Vec<u8>,
110
    /// number of bytes set in crypto fragment data to client
111
    crypto_fraglen_tc: u32,
112
    /// crypto fragment data already seen and reassembled to server
113
    crypto_frag_ts: Vec<u8>,
114
    /// number of bytes set in crypto fragment data to server
115
    crypto_fraglen_ts: u32,
116
    hello_tc: bool,
117
    hello_ts: bool,
118
    has_retried: bool,
119
    transactions: VecDeque<QuicTransaction>,
120
}
121
122
impl Default for QuicState {
123
12.6k
    fn default() -> Self {
124
12.6k
        Self {
125
12.6k
            state_data: AppLayerStateData::new(),
126
12.6k
            max_tx_id: 0,
127
12.6k
            keys: None,
128
12.6k
            crypto_frag_tc: Vec::new(),
129
12.6k
            crypto_frag_ts: Vec::new(),
130
12.6k
            crypto_fraglen_tc: 0,
131
12.6k
            crypto_fraglen_ts: 0,
132
12.6k
            hello_tc: false,
133
12.6k
            hello_ts: false,
134
12.6k
            has_retried: false,
135
12.6k
            transactions: VecDeque::new(),
136
12.6k
        }
137
12.6k
    }
138
}
139
140
impl QuicState {
141
12.6k
    fn new() -> Self {
142
12.6k
        Self::default()
143
12.6k
    }
144
145
    // Free a transaction by ID.
146
1.10M
    fn free_tx(&mut self, tx_id: u64) {
147
1.10M
        let tx = self
148
1.10M
            .transactions
149
1.10M
            .iter()
150
1.10M
            .position(|tx| tx.tx_id == tx_id + 1);
151
1.10M
        if let Some(idx) = tx {
152
1.10M
            let _ = self.transactions.remove(idx);
153
1.10M
        }
154
1.10M
    }
155
156
3.61k
    fn get_tx(&mut self, tx_id: u64) -> Option<&QuicTransaction> {
157
4.28k
        self.transactions.iter().find(|&tx| tx.tx_id == tx_id + 1)
158
3.61k
    }
159
160
1.75M
    fn new_tx(
161
1.75M
        &mut self, header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
162
1.75M
        extb: Vec<QuicTlsExtension>, ja3: Option<String>, ja4: Option<String>, client: bool,
163
1.75M
        frag_long: bool,
164
1.75M
    ) {
165
1.75M
        let mut tx = QuicTransaction::new(header, data, sni, ua, extb, ja3, ja4, client);
166
1.75M
        self.max_tx_id += 1;
167
1.75M
        tx.tx_id = self.max_tx_id;
168
1.75M
        if frag_long {
169
11.7k
            tx.tx_data.set_event(QuicEvent::CryptoFragTooLong as u8);
170
1.74M
        }
171
1.75M
        self.transactions.push_back(tx);
172
1.75M
    }
173
174
1.13M
    fn tx_iterator(
175
1.13M
        &mut self, min_tx_id: u64, state: &mut u64,
176
1.13M
    ) -> Option<(&QuicTransaction, u64, bool)> {
177
1.13M
        let mut index = *state as usize;
178
1.13M
        let len = self.transactions.len();
179
180
1.14M
        while index < len {
181
1.11M
            let tx = &self.transactions[index];
182
1.11M
            if tx.tx_id < min_tx_id + 1 {
183
791
                index += 1;
184
791
                continue;
185
1.11M
            }
186
1.11M
            *state = index as u64;
187
1.11M
            return Some((tx, tx.tx_id - 1, (len - index) > 1));
188
        }
189
190
24.5k
        return None;
191
1.13M
    }
192
193
3.49k
    fn decrypt<'a>(
194
3.49k
        &mut self, to_server: bool, header: &QuicHeader, framebuf: &'a [u8], buf: &'a [u8],
195
3.49k
        hlen: usize, output: &'a mut Vec<u8>,
196
3.49k
    ) -> Result<usize, ()> {
197
3.49k
        if let Some(keys) = &self.keys {
198
3.49k
            let hkey = if to_server {
199
3.41k
                &keys.remote.header
200
            } else {
201
80
                &keys.local.header
202
            };
203
3.49k
            if framebuf.len() < PKT_NUM_BUF_MAX_LEN + AES128_KEY_LEN {
204
43
                return Err(());
205
3.45k
            }
206
3.45k
            let h2len = hlen + usize::from(header.length);
207
3.45k
            let mut h2 = Vec::with_capacity(h2len);
208
3.45k
            h2.extend_from_slice(&buf[..h2len]);
209
3.45k
            let mut h20 = h2[0];
210
3.45k
            let mut pktnum_buf = Vec::with_capacity(PKT_NUM_BUF_MAX_LEN);
211
3.45k
            pktnum_buf.extend_from_slice(&h2[hlen..hlen + PKT_NUM_BUF_MAX_LEN]);
212
3.45k
            let r1 = hkey.decrypt_in_place(
213
3.45k
                &h2[hlen + PKT_NUM_BUF_MAX_LEN..hlen + PKT_NUM_BUF_MAX_LEN + AES128_KEY_LEN],
214
3.45k
                &mut h20,
215
3.45k
                &mut pktnum_buf,
216
            );
217
3.45k
            if r1.is_err() {
218
0
                return Err(());
219
3.45k
            }
220
            // mutate one at a time
221
3.45k
            h2[0] = h20;
222
3.45k
            let _ = &h2[hlen..hlen + 1 + ((h20 & 3) as usize)]
223
3.45k
                .copy_from_slice(&pktnum_buf[..1 + ((h20 & 3) as usize)]);
224
3.45k
            let pkt_num = quic_pkt_num(&h2[hlen..hlen + 1 + ((h20 & 3) as usize)]);
225
3.45k
            if framebuf.len() < 1 + ((h20 & 3) as usize) {
226
0
                return Err(());
227
3.45k
            }
228
3.45k
            output.extend_from_slice(&framebuf[1 + ((h20 & 3) as usize)..]);
229
3.45k
            let pkey = if to_server {
230
3.38k
                &keys.remote.packet
231
            } else {
232
75
                &keys.local.packet
233
            };
234
3.45k
            let r = pkey.decrypt_in_place(pkt_num, &h2[..hlen + 1 + ((h20 & 3) as usize)], output);
235
3.45k
            if let Ok(r2) = r {
236
84
                return Ok(r2.len());
237
3.37k
            }
238
0
        }
239
3.37k
        return Err(());
240
3.49k
    }
241
242
1.74M
    fn handle_frames(&mut self, data: QuicData, header: QuicHeader, to_server: bool) {
243
1.74M
        let mut sni: Option<Vec<u8>> = None;
244
1.74M
        let mut ua: Option<Vec<u8>> = None;
245
1.74M
        let mut ja3: Option<String> = None;
246
1.74M
        let mut ja4: Option<String> = None;
247
1.74M
        let mut extv: Vec<QuicTlsExtension> = Vec::new();
248
1.74M
        let mut frag_long = false;
249
3.19M
        for frame in &data.frames {
250
1.45M
            match frame {
251
86.5k
                Frame::Stream(s) => {
252
86.5k
                    if let Some(tags) = &s.tags {
253
38.0k
                        for (tag, value) in tags {
254
29.6k
                            if tag == &StreamTag::Sni {
255
1.76k
                                sni = Some(value.to_vec());
256
27.8k
                            } else if tag == &StreamTag::Uaid {
257
1.73k
                                ua = Some(value.to_vec());
258
26.1k
                            }
259
29.6k
                            if sni.is_some() && ua.is_some() {
260
994
                                break;
261
28.6k
                            }
262
                        }
263
77.1k
                    }
264
                }
265
601k
                Frame::CryptoFrag(frag) => {
266
                    // means we had some fragments but not full TLS hello
267
                    // save it for a later packet
268
601k
                    if to_server {
269
                        // use a hardcoded limit to not grow indefinitely
270
198k
                        if frag.length < QUIC_MAX_CRYPTO_FRAG_LEN {
271
192k
                            self.crypto_frag_ts.clone_from(&frag.data);
272
192k
                            self.crypto_fraglen_ts = frag.offset as u32;
273
192k
                        } else {
274
6.58k
                            frag_long = true;
275
6.58k
                        }
276
403k
                    } else if frag.length < QUIC_MAX_CRYPTO_FRAG_LEN {
277
398k
                        self.crypto_frag_tc.clone_from(&frag.data);
278
398k
                        self.crypto_fraglen_tc = frag.offset as u32;
279
398k
                    } else {
280
5.14k
                        frag_long = true;
281
5.14k
                    }
282
                }
283
40.6k
                Frame::Crypto(c) => {
284
40.6k
                    if let Some(ja3str) = &c.ja3 {
285
40.6k
                        ja3 = Some(ja3str.clone());
286
40.6k
                    }
287
                    // we only do client fingerprints for now
288
40.6k
                    if to_server {
289
                        // our hash is complete, let's only use strings from
290
                        // now on
291
38.5k
                        if let Some(ref rja4) = c.ja4 {
292
34.6k
                            ja4 = Some(rja4.get_hash());
293
34.6k
                        }
294
2.09k
                    }
295
2.51M
                    for e in &c.extv {
296
2.47M
                        if e.etype == TlsExtensionType::ServerName && !e.values.is_empty() {
297
826
                            sni = Some(e.values[0].to_vec());
298
2.47M
                        }
299
                    }
300
40.6k
                    extv.extend_from_slice(&c.extv);
301
40.6k
                    if to_server {
302
38.5k
                        self.hello_ts = true
303
                    } else {
304
2.09k
                        self.hello_tc = true
305
                    }
306
                }
307
722k
                _ => {}
308
            }
309
        }
310
1.74M
        self.new_tx(header, data, sni, ua, extv, ja3, ja4, to_server, frag_long);
311
1.74M
    }
312
313
10.8k
    fn set_event_notx(&mut self, event: QuicEvent, header: QuicHeader, client: bool) {
314
10.8k
        let mut tx = QuicTransaction::new_empty(client, header);
315
10.8k
        self.max_tx_id += 1;
316
10.8k
        tx.tx_id = self.max_tx_id;
317
10.8k
        tx.tx_data.set_event(event as u8);
318
10.8k
        self.transactions.push_back(tx);
319
10.8k
    }
320
321
287k
    fn parse(&mut self, input: &[u8], to_server: bool) -> bool {
322
        // so as to loop over multiple quic headers in one packet
323
287k
        let mut buf = input;
324
2.04M
        while !buf.is_empty() {
325
1.78M
            match QuicHeader::from_bytes(buf, DEFAULT_DCID_LEN) {
326
1.78M
                Ok((rest, header)) => {
327
1.78M
                    if (to_server && self.hello_ts) || (!to_server && self.hello_tc) {
328
                        // payload is encrypted, stop parsing here
329
1.23k
                        return true;
330
1.78M
                    }
331
1.78M
                    if header.ty == QuicType::Short {
332
                        // nothing to get
333
20.5k
                        return true;
334
1.76M
                    }
335
336
                    // unprotect/decrypt packet
337
1.76M
                    if self.keys.is_none() && header.ty == QuicType::Initial {
338
1.71M
                        self.keys = quic_keys_initial(u32::from(header.version), &header.dcid);
339
1.71M
                    } else if !to_server
340
4.66k
                        && self.keys.is_some()
341
1.41k
                        && header.ty == QuicType::Retry
342
1.10k
                        && !self.has_retried
343
41
                    {
344
41
                        // a retry packet discards the current keys, client will resend an initial packet with new keys
345
41
                        self.hello_ts = false;
346
41
                        self.keys = None;
347
41
                        // RFC 9000 17.2.5.2 After the client has received and processed an Initial or Retry packet
348
41
                        // from the server, it MUST discard any subsequent Retry packets that it receives.
349
41
                        self.has_retried = true;
350
46.6k
                    }
351
                    // header.length was checked against rest.len() during parsing
352
1.76M
                    let (mut framebuf, next_buf) = rest.split_at(header.length.into());
353
1.76M
                    if header.ty != QuicType::Initial {
354
                        // only version is interesting, no frames
355
8.80k
                        self.new_tx(
356
8.80k
                            header,
357
8.80k
                            QuicData { frames: Vec::new() },
358
8.80k
                            None,
359
8.80k
                            None,
360
8.80k
                            Vec::new(),
361
8.80k
                            None,
362
8.80k
                            None,
363
8.80k
                            to_server,
364
                            false,
365
                        );
366
8.80k
                        buf = next_buf;
367
8.80k
                        continue;
368
1.75M
                    }
369
1.75M
                    let hlen = buf.len() - rest.len();
370
                    let mut output;
371
1.75M
                    if self.keys.is_some() && !framebuf.is_empty() {
372
3.49k
                        output = Vec::with_capacity(framebuf.len() + 4);
373
84
                        if let Ok(dlen) =
374
3.49k
                            self.decrypt(to_server, &header, framebuf, buf, hlen, &mut output)
375
84
                        {
376
84
                            output.resize(dlen, 0);
377
84
                        } else {
378
3.41k
                            self.set_event_notx(QuicEvent::FailedDecrypt, header, to_server);
379
3.41k
                            return false;
380
                        }
381
84
                        framebuf = &output;
382
1.75M
                    }
383
1.75M
                    buf = next_buf;
384
385
1.75M
                    let mut frag = Vec::new();
386
                    // take the current fragment and reset it in the state
387
1.75M
                    let past_frag = if to_server {
388
1.06M
                        std::mem::swap(&mut self.crypto_frag_ts, &mut frag);
389
1.06M
                        &frag
390
                    } else {
391
686k
                        std::mem::swap(&mut self.crypto_frag_tc, &mut frag);
392
686k
                        &frag
393
                    };
394
1.75M
                    let past_fraglen = if to_server {
395
1.06M
                        self.crypto_fraglen_ts
396
                    } else {
397
686k
                        self.crypto_fraglen_tc
398
                    };
399
1.75M
                    if to_server {
400
1.06M
                        self.crypto_fraglen_ts = 0
401
                    } else {
402
686k
                        self.crypto_fraglen_tc = 0
403
                    }
404
1.75M
                    match QuicData::from_bytes(framebuf, past_frag, past_fraglen) {
405
1.74M
                        Ok(data) => {
406
1.74M
                            self.handle_frames(data, header, to_server);
407
1.74M
                        }
408
7.40k
                        Err(_e) => {
409
7.40k
                            self.set_event_notx(QuicEvent::ErrorOnData, header, to_server);
410
7.40k
                            return false;
411
                        }
412
                    }
413
                }
414
3.21k
                Err(_e) => {
415
                    // should we make an event with an empty header ?
416
3.21k
                    return false;
417
                }
418
            }
419
        }
420
251k
        return true;
421
287k
    }
422
}
423
424
#[no_mangle]
425
12.6k
pub extern "C" fn rs_quic_state_new(
426
12.6k
    _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
427
12.6k
) -> *mut std::os::raw::c_void {
428
12.6k
    let state = QuicState::new();
429
12.6k
    let boxed = Box::new(state);
430
12.6k
    return Box::into_raw(boxed) as *mut _;
431
12.6k
}
432
433
#[no_mangle]
434
12.6k
pub extern "C" fn rs_quic_state_free(state: *mut std::os::raw::c_void) {
435
    // Just unbox...
436
12.6k
    std::mem::drop(unsafe { Box::from_raw(state as *mut QuicState) });
437
12.6k
}
438
439
#[no_mangle]
440
1.10M
pub unsafe extern "C" fn rs_quic_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
441
1.10M
    let state = cast_pointer!(state, QuicState);
442
1.10M
    state.free_tx(tx_id);
443
1.10M
}
444
445
#[no_mangle]
446
2.38k
pub unsafe extern "C" fn rs_quic_probing_parser(
447
2.38k
    _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
448
2.38k
) -> AppProto {
449
2.38k
    if input.is_null() {
450
0
        return ALPROTO_UNKNOWN;
451
2.38k
    }
452
2.38k
    let slice = build_slice!(input, input_len as usize);
453
454
2.38k
    if QuicHeader::from_bytes(slice, DEFAULT_DCID_LEN).is_ok() {
455
1.84k
        return ALPROTO_QUIC;
456
    } else {
457
538
        return ALPROTO_FAILED;
458
    }
459
2.38k
}
460
461
#[no_mangle]
462
127k
pub unsafe extern "C" fn rs_quic_parse_tc(
463
127k
    _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
464
127k
    stream_slice: StreamSlice, _data: *const std::os::raw::c_void,
465
127k
) -> AppLayerResult {
466
127k
    let state = cast_pointer!(state, QuicState);
467
127k
    let buf = stream_slice.as_slice();
468
469
127k
    if state.parse(buf, false) {
470
127k
        return AppLayerResult::ok();
471
    } else {
472
528
        return AppLayerResult::err();
473
    }
474
127k
}
475
476
#[no_mangle]
477
159k
pub unsafe extern "C" fn rs_quic_parse_ts(
478
159k
    _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
479
159k
    stream_slice: StreamSlice, _data: *const std::os::raw::c_void,
480
159k
) -> AppLayerResult {
481
159k
    let state = cast_pointer!(state, QuicState);
482
159k
    let buf = stream_slice.as_slice();
483
484
159k
    if state.parse(buf, true) {
485
146k
        return AppLayerResult::ok();
486
    } else {
487
13.4k
        return AppLayerResult::err();
488
    }
489
159k
}
490
491
#[no_mangle]
492
3.61k
pub unsafe extern "C" fn rs_quic_state_get_tx(
493
3.61k
    state: *mut std::os::raw::c_void, tx_id: u64,
494
3.61k
) -> *mut std::os::raw::c_void {
495
3.61k
    let state = cast_pointer!(state, QuicState);
496
3.61k
    match state.get_tx(tx_id) {
497
3.61k
        Some(tx) => {
498
3.61k
            return tx as *const _ as *mut _;
499
        }
500
        None => {
501
2
            return std::ptr::null_mut();
502
        }
503
    }
504
3.61k
}
505
506
#[no_mangle]
507
850k
pub unsafe extern "C" fn rs_quic_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
508
850k
    let state = cast_pointer!(state, QuicState);
509
850k
    return state.max_tx_id;
510
850k
}
511
512
#[no_mangle]
513
0
pub extern "C" fn rs_quic_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int {
514
    // This parser uses 1 to signal transaction completion status.
515
0
    return 1;
516
0
}
517
518
#[no_mangle]
519
2.22M
pub unsafe extern "C" fn rs_quic_tx_get_alstate_progress(
520
2.22M
    tx: *mut std::os::raw::c_void, _direction: u8,
521
2.22M
) -> std::os::raw::c_int {
522
2.22M
    let _tx = cast_pointer!(tx, QuicTransaction);
523
2.22M
    return 1;
524
2.22M
}
525
526
#[no_mangle]
527
1.13M
pub unsafe extern "C" fn rs_quic_state_get_tx_iterator(
528
1.13M
    _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
529
1.13M
    _max_tx_id: u64, istate: &mut u64,
530
1.13M
) -> applayer::AppLayerGetTxIterTuple {
531
1.13M
    let state = cast_pointer!(state, QuicState);
532
1.13M
    match state.tx_iterator(min_tx_id, istate) {
533
1.11M
        Some((tx, out_tx_id, has_next)) => {
534
1.11M
            let c_tx = tx as *const _ as *mut _;
535
1.11M
            let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next);
536
1.11M
            return ires;
537
        }
538
        None => {
539
24.5k
            return applayer::AppLayerGetTxIterTuple::not_found();
540
        }
541
    }
542
1.13M
}
543
544
export_tx_data_get!(rs_quic_get_tx_data, QuicTransaction);
545
export_state_data_get!(rs_quic_get_state_data, QuicState);
546
547
// Parser name as a C style string.
548
const PARSER_NAME: &[u8] = b"quic\0";
549
550
#[no_mangle]
551
34
pub unsafe extern "C" fn rs_quic_register_parser() {
552
34
    let default_port = CString::new("[443,80]").unwrap();
553
34
    let parser = RustParser {
554
34
        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
555
34
        default_port: default_port.as_ptr(),
556
34
        ipproto: IPPROTO_UDP,
557
34
        probe_ts: Some(rs_quic_probing_parser),
558
34
        probe_tc: Some(rs_quic_probing_parser),
559
34
        min_depth: 0,
560
34
        max_depth: 16,
561
34
        state_new: rs_quic_state_new,
562
34
        state_free: rs_quic_state_free,
563
34
        tx_free: rs_quic_state_tx_free,
564
34
        parse_ts: rs_quic_parse_ts,
565
34
        parse_tc: rs_quic_parse_tc,
566
34
        get_tx_count: rs_quic_state_get_tx_count,
567
34
        get_tx: rs_quic_state_get_tx,
568
34
        tx_comp_st_ts: 1,
569
34
        tx_comp_st_tc: 1,
570
34
        tx_get_progress: rs_quic_tx_get_alstate_progress,
571
34
        get_eventinfo: Some(QuicEvent::get_event_info),
572
34
        get_eventinfo_byid: Some(QuicEvent::get_event_info_by_id),
573
34
        localstorage_new: None,
574
34
        localstorage_free: None,
575
34
        get_tx_files: None,
576
34
        get_tx_iterator: Some(rs_quic_state_get_tx_iterator),
577
34
        get_tx_data: rs_quic_get_tx_data,
578
34
        get_state_data: rs_quic_get_state_data,
579
34
        apply_tx_config: None,
580
34
        flags: 0,
581
34
        truncate: None,
582
34
        get_frame_id_by_name: None,
583
34
        get_frame_name_by_id: None,
584
34
    };
585
586
34
    let ip_proto_str = CString::new("udp").unwrap();
587
588
34
    if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
589
34
        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
590
34
        ALPROTO_QUIC = alproto;
591
34
        if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
592
34
            let _ = AppLayerRegisterParser(&parser, alproto);
593
34
        }
594
        SCLogDebug!("Rust quic parser registered.");
595
0
    } else {
596
0
        SCLogDebug!("Protocol detector and parser disabled for quic.");
597
0
    }
598
34
}